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

1.1       www         1: # The LearningOnline Network with CAPA
                      2: # Handler to set parameters for assessments
                      3: #
1.624   ! raeburn     4: # $Id: lonparmset.pm,v 1.623 2025/06/30 20:29:03 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 {
                   1288:     return <<'ENDSCRIPT';
                   1289: 
                   1290: function validateParms() {
                   1291:     var textRegExp = /^settext_/;
                   1292:     var tailLenient = /\.lenient$/;
                   1293:     var patternRelWeight = /^\-?[\d.]+$/;
                   1294:     var patternLenientStd = /^(yes|no|default)$/;
1.597     raeburn  1295:     var ipRegExp = /^setip/;
1.549     raeburn  1296:     var ipallowRegExp = /^setipallow_/;
                   1297:     var ipdenyRegExp = /^setipdeny_/; 
1.622     raeburn  1298:     var graceRegExp = /^setgrace_/;
1.597     raeburn  1299:     var deeplinkRegExp = /^deeplink_/;
1.601     raeburn  1300:     var dlListScopeRegExp = /^deeplink_(state|others|listing|scope)_/; 
                   1301:     var dlLinkProtectRegExp = /^deeplink_protect_/;
                   1302:     var dlLtidRegExp = /^deeplink_ltid_/;
                   1303:     var dlLticRegExp = /^deeplink_ltic_/;
1.597     raeburn  1304:     var dlKeyRegExp = /^deeplink_key_/;
                   1305:     var dlMenusRegExp = /^deeplink_menus_/;
                   1306:     var dlCollsRegExp = /^deeplink_colls_/;
1.613     raeburn  1307:     var dlTargetRegExp = /^deeplink_target_/;
1.616     raeburn  1308:     var dlExitRegExp = /^deeplink_exit_/;
                   1309:     var dlExitTextRegExp = /^deeplink_exittext_/;
1.549     raeburn  1310:     var patternIP = /[\[\]\*\.a-zA-Z\d\-]+/;
1.623     raeburn  1311:     var patternGrace = /^\d+:(0|1)\.?\d*:(0|1)\$/;
1.616     raeburn  1312:     var numelements = document.parmform.elements.length;
                   1313:     if ((typeof(numelements) != 'undefined') && (numelements != null)) {
                   1314:         if (numelements) {
                   1315:             for (i=0; i<numelements; i++) {
1.549     raeburn  1316:                 var name=document.parmform.elements[i].name;
1.588     raeburn  1317:                 if (textRegExp.test(name)) {
1.549     raeburn  1318:                     var identifier = name.replace(textRegExp,'');
                   1319:                     if (tailLenient.test(identifier)) {
                   1320:                         if (document.parmform.elements['set_'+identifier].length) {
                   1321:                             for (var j=0; j<document.parmform.elements['set_'+identifier].length; j++) {
                   1322:                                 if (document.parmform.elements['set_'+identifier][j].checked) {
                   1323:                                     if (!(patternLenientStd.test(document.parmform.elements['set_'+identifier][j].value))) {
                   1324:                                         var relweight = document.parmform.elements[i].value;
                   1325:                                         relweight = relweight.replace(/^\s+|\s+$/g,'');
                   1326:                                         if (!patternRelWeight.test(relweight)) {
                   1327:                                             relweight = '0.0';
                   1328:                                         }
                   1329:                                         if (document.parmform.elements['set_'+identifier][j].value == 'weighted') {
                   1330:                                             document.parmform.elements['set_'+identifier][j].value = relweight;
                   1331:                                         } else {
                   1332:                                             document.parmform.elements['set_'+identifier][j].value += ','+relweight;
                   1333:                                         }
                   1334:                                     }
                   1335:                                     break;
                   1336:                                 }
                   1337:                             }
                   1338:                         }
                   1339:                     }
1.597     raeburn  1340:                 } else if (ipRegExp.test(name)) {
                   1341:                     if (ipallowRegExp.test(name)) {
                   1342:                         var identifier = name.replace(ipallowRegExp,'');
                   1343:                         var possallow = document.parmform.elements[i].value;
                   1344:                         possallow = possallow.replace(/^\s+|\s+$/g,'');
                   1345:                         if (patternIP.test(possallow)) {
                   1346:                             if (document.parmform.elements['set_'+identifier].value) {
                   1347:                                 possallow = ','+possallow;
                   1348:                             }
                   1349:                             document.parmform.elements['set_'+identifier].value += possallow;
                   1350:                         }
                   1351:                     } else if (ipdenyRegExp.test(name)) {
                   1352:                         var identifier = name.replace(ipdenyRegExp,'');
                   1353:                         var possdeny = document.parmform.elements[i].value;
                   1354:                         possdeny = possdeny.replace(/^\s+|\s+$/g,'');
                   1355:                         if (patternIP.test(possdeny)) {
                   1356:                             possdeny = '!'+possdeny;
                   1357:                             if (document.parmform.elements['set_'+identifier].value) {
                   1358:                                 possdeny = ','+possdeny;
                   1359:                             }
                   1360:                             document.parmform.elements['set_'+identifier].value += possdeny;
1.588     raeburn  1361:                         }
                   1362:                     }
                   1363:                 } else if (deeplinkRegExp.test(name)) {
1.597     raeburn  1364:                     if (dlListScopeRegExp.test(name)) {
                   1365:                         var identifier =  name.replace(dlListScopeRegExp,'');
                   1366:                         var idx = document.parmform.elements[i].selectedIndex;
                   1367:                         if (idx > 0) { 
                   1368:                             var possdeeplink = document.parmform.elements[i].options[idx].value
                   1369:                             possdeeplink = possdeeplink.replace(/^\s+|\s+$/g,'');
                   1370:                             if (document.parmform.elements['set_'+identifier].value) {
                   1371:                                 possdeeplink = ','+possdeeplink;
                   1372:                             }
                   1373:                             document.parmform.elements['set_'+identifier].value += possdeeplink;
                   1374:                         }
1.601     raeburn  1375:                     } else if (dlLinkProtectRegExp.test(name)) {
1.597     raeburn  1376:                         if (document.parmform.elements[i].checked) {
1.601     raeburn  1377:                             var identifier =  name.replace(dlLinkProtectRegExp,'');
1.597     raeburn  1378:                             var posslinkurl = document.parmform.elements[i].value;
                   1379:                             posslinkurl = posslinkurl.replace(/^\s+|\s+$/g,'');
                   1380:                             if (document.parmform.elements['set_'+identifier].value) {
                   1381:                                 posslinkurl = ','+posslinkurl;
                   1382:                             }
                   1383:                             document.parmform.elements['set_'+identifier].value += posslinkurl;
                   1384:                         }
1.601     raeburn  1385:                     } else if (dlLtidRegExp.test(name)) {
                   1386:                         var identifier = name.replace(dlLtidRegExp,'');
                   1387:                         if (isRadioSet('deeplink_protect_'+identifier,'ltid')) {
                   1388:                             var possltid = document.parmform.elements[i].value;
                   1389:                             possltid = possltid.replace(/\D+/g,'');
                   1390:                             if (possltid.length) {
1.597     raeburn  1391:                                 if (document.parmform.elements['set_'+identifier].value) {
1.601     raeburn  1392:                                     possltid = ':'+possltid;
1.597     raeburn  1393:                                 }
1.601     raeburn  1394:                                 document.parmform.elements['set_'+identifier].value += possltid;
1.597     raeburn  1395:                             } else {
                   1396:                                 document.parmform.elements['set_'+identifier].value = '';
1.601     raeburn  1397:                                 alert("A link type of 'domain LTI launch' was selected but no domain LTI launcher was selected.\nPlease select one, or choose a different supported link type.");
1.597     raeburn  1398:                                 return false;  
                   1399:                             }
                   1400:                         }
1.601     raeburn  1401:                     } else if (dlLticRegExp.test(name)) {
                   1402:                         var identifier = name.replace(dlLticRegExp,'');
                   1403:                         if (isRadioSet('deeplink_protect_'+identifier,'ltic')) {
                   1404:                             var possltic = document.parmform.elements[i].value;
                   1405:                             possltic = possltic.replace(/\D+/g,'');
                   1406:                             if (possltic.length) {
                   1407:                                 if (document.parmform.elements['set_'+identifier].value) {
                   1408:                                     possltic = ':'+possltic;
                   1409:                                 }
                   1410:                                 document.parmform.elements['set_'+identifier].value += possltic;
                   1411:                             } else {
                   1412:                                 document.parmform.elements['set_'+identifier].value = '';
                   1413:                                 alert("A link type of 'course LTI launch' was selected but no course LTI launcher was selected.\nPlease select one, or choose a different supported link type.");
                   1414:                                 return false;
                   1415:                             }
                   1416:                         }
1.597     raeburn  1417:                     } else if (dlKeyRegExp.test(name)) {
                   1418:                         var identifier = name.replace(dlKeyRegExp,'');
1.601     raeburn  1419:                         if (isRadioSet('deeplink_protect_'+identifier,'key')) {
1.597     raeburn  1420:                             var posskey = document.parmform.elements[i].value;
                   1421:                             posskey = posskey.replace(/^\s+|\s+$/g,'');
                   1422:                             var origlength = posskey.length;
                   1423:                             posskey = posskey.replace(/[^a-zA-Z\d_.!@#$%^&*()+=-]/g,'');
                   1424:                             var newlength = posskey.length;
                   1425:                             if (newlength > 0) {
                   1426:                                 var change = origlength - newlength;
                   1427:                                 if (change) {
                   1428:                                     alert(change+' disallowed character(s) removed from deeplink key'); 
                   1429:                                 }
                   1430:                                 if (document.parmform.elements['set_'+identifier].value) {
                   1431:                                     posskey = ':'+posskey;
                   1432:                                 }
                   1433:                                 document.parmform.elements['set_'+identifier].value += posskey;
                   1434:                             } else {
                   1435:                                 document.parmform.elements['set_'+identifier].value = '';
                   1436:                                 if (newlength < origlength) {
                   1437:                                     alert("A link type of 'deep with key' was selected but the key value was blank, after removing disallowed characters.\nPlease enter a key using one or more of: a-zA-Z0-9_.!@#$%^&*()+=-");
                   1438:                                 } else {
                   1439:                                     alert("A link type of 'deep with key' was selected but the key value was blank.\nPlease enter a key.");
                   1440:                                 }
                   1441:                                 return false;
                   1442:                             }
                   1443:                         }
                   1444:                     } else if (dlMenusRegExp.test(name)) {
                   1445:                         if (document.parmform.elements[i].checked) {
                   1446:                             var identifier =  name.replace(dlMenusRegExp,'');
                   1447:                             var posslinkmenu = document.parmform.elements[i].value;
                   1448:                             posslinkmenu = posslinkmenu.replace(/^\s+|\s+$/g,'');
                   1449:                             if (posslinkmenu == 'std') {
                   1450:                                 posslinkmenu = '0';
                   1451:                                 if (document.parmform.elements['set_'+identifier].value) {
                   1452:                                     posslinkmenu = ','+posslinkmenu;
                   1453:                                 }
                   1454:                                 document.parmform.elements['set_'+identifier].value += posslinkmenu;
                   1455:                             }
                   1456:                         }
                   1457:                     } else if (dlCollsRegExp.test(name)) {
                   1458:                         var identifier =  name.replace(dlCollsRegExp,'');
                   1459:                         if (isRadioSet('deeplink_menus_'+identifier,'colls')) {
                   1460:                             var posslinkmenu = document.parmform.elements[i].value;
                   1461:                             if (document.parmform.elements['set_'+identifier].value) {
                   1462:                                 posslinkmenu = ','+posslinkmenu;
                   1463:                             }
                   1464:                             document.parmform.elements['set_'+identifier].value += posslinkmenu;
                   1465:                         }
1.614     raeburn  1466:                     } else if (dlTargetRegExp.test(name)) {
                   1467:                         var identifier =  name.replace(dlTargetRegExp,'');
1.613     raeburn  1468:                         var idx = document.parmform.elements[i].selectedIndex;
                   1469:                         if (idx > 0) {
1.616     raeburn  1470:                             var linktarget = document.parmform.elements[i].options[idx].value
                   1471:                             linktarget = linktarget.replace(/^\s+|\s+$/g,'');
                   1472:                             if (document.parmform.elements['set_'+identifier].value) {
                   1473:                                 linktarget = ','+linktarget;
                   1474:                             }
                   1475:                             document.parmform.elements['set_'+identifier].value += linktarget;
                   1476:                         }
                   1477:                     } else if (dlExitRegExp.test(name)) {
                   1478:                         if (document.parmform.elements[i].checked) {
                   1479:                             var identifier =  name.replace(dlExitRegExp,'');
                   1480:                             var posslinkexit = document.parmform.elements[i].value;
                   1481:                             posslinkexit = posslinkexit.replace(/^\s+|\s+$/g,'');
1.613     raeburn  1482:                             if (document.parmform.elements['set_'+identifier].value) {
1.616     raeburn  1483:                                 posslinkexit = ','+posslinkexit;
                   1484:                             }
                   1485:                             document.parmform.elements['set_'+identifier].value += posslinkexit;
                   1486:                         }
                   1487:                     } else if (dlExitTextRegExp.test(name)) {
                   1488:                         var identifier = name.replace(dlExitTextRegExp,'');
                   1489:                         if ((isRadioSet('deeplink_exit_'+identifier,'yes')) ||
                   1490:                             (isRadioSet('deeplink_exit_'+identifier,'url'))) {
                   1491:                             var posstext = document.parmform.elements[i].value;
                   1492:                             posstext = posstext.replace(/^\s+|\s+$/g,'');
                   1493:                             var origlength = posstext.length;
                   1494:                             posstext = posstext.replace(/[:;'",]/g,'');
                   1495:                             var newlength = posstext.length;
                   1496:                             if (newlength > 0) {
                   1497:                                 var change = origlength - newlength;
                   1498:                                 if (change) {
                   1499:                                     alert(change+' disallowed character(s) removed from Exit Button text');
                   1500:                                 }
                   1501:                                 if (posstext !== 'Exit Tool') {
                   1502:                                     posstext = ':'+posstext;
                   1503:                                     document.parmform.elements['set_'+identifier].value += posstext;
                   1504:                                 }
                   1505:                             } else {
                   1506:                                 document.parmform.elements['set_'+identifier].value = '';
                   1507:                                 if (newlength < origlength) {
                   1508:                                     alert("An exit link type of 'In use' was selected but the button text value was blank, after removing disallowed characters.\nDisallowed characters are ,\":;'");
                   1509:                                 } else {
                   1510:                                     alert("An exit link type of 'In use' was selected but the button text value was blank.\nPlease enter the text to use.");
                   1511:                                 }
                   1512:                                 return false;
1.613     raeburn  1513:                             }
                   1514:                         }
1.549     raeburn  1515:                     }
1.622     raeburn  1516:                 } else if (graceRegExp.test(name)) {
                   1517:                     var identifier = name.replace(graceRegExp,'');
                   1518:                     var divElem = document.parmform.elements[i].closest('div'); 
                   1519:                     var timeSels = divElem.getElementsByTagName("select");
                   1520:                     var total = 0;
1.623     raeburn  1521:                     var numnotnull = 0;
1.622     raeburn  1522:                     if (timeSels.length) {
                   1523:                          for (var j=0; j<timeSels.length; j++) {
                   1524:                             var sname = timeSels[j].getAttribute('name');
1.623     raeburn  1525:                             var value = timeSels[j].options[timeSels[j].selectedIndex].value;
                   1526:                             if ((value !== null) && (value !== '') && (value !== 'undefined')) {
                   1527:                                 numnotnull ++;
                   1528:                                 var poss = parseInt(value);
                   1529:                                 if (sname == 'weeks_'+identifier) {
                   1530:                                     if ((poss > 0) && (poss <= 52)) {
                   1531:                                         total += (poss * 604800);
                   1532:                                     }
                   1533:                                 } else if (sname == 'days_'+identifier) {
                   1534:                                     if ((poss > 0) && (poss <= 6)) {
                   1535:                                         total += (poss * 86400); 
                   1536:                                     }
                   1537:                                 } else if (sname == 'hours_'+identifier) {
                   1538:                                     if ((poss > 0) && (poss < 24)) {
                   1539:                                         total += (poss * 3600);
                   1540:                                     }
                   1541:                                 } else if (sname == 'minutes_'+identifier) {
                   1542:                                     if ((poss > 0) && (poss < 60)) {
                   1543:                                         total += (poss * 60);
                   1544:                                     }
1.622     raeburn  1545:                                 }
                   1546:                             }
                   1547:                         }
                   1548:                     }
1.623     raeburn  1549:                     if (!numnotnull) {
                   1550:                         total = '';
                   1551:                     }
1.622     raeburn  1552:                     var inputElems = divElem.getElementsByTagName("input");
                   1553:                     var frac = '';
                   1554:                     var grad = '';
                   1555:                     if (inputElems.length) {
                   1556:                         for (var j=0; j<inputElems.length; j++) {
                   1557:                             var iname = inputElems[j].getAttribute('name');
                   1558:                             if (iname == 'frac_'+identifier) {
                   1559:                                 var ival = inputElems[j].value;
                   1560:                                 ival.trim();
1.623     raeburn  1561:                                 if ((ival != '') && (value != 'undefined')) {
                   1562:                                     var poss = parseFloat(ival);
                   1563:                                     if ((typeof poss === 'number') && (!isNaN(poss))) {
                   1564:                                         if ((poss => 0) && (poss <= 1)) {
                   1565:                                             frac = poss;
                   1566:                                             numnotnull ++;
                   1567:                                         }
1.622     raeburn  1568:                                     }
                   1569:                                 }
                   1570:                             } else if (iname == 'grad_'+identifier) {
                   1571:                                 if (inputElems[j].checked) {
                   1572:                                     grad = 1;
                   1573:                                 } else {
                   1574:                                     grad = 0;
                   1575:                                 }
                   1576:                             }
                   1577:                         }
                   1578:                     }
1.623     raeburn  1579:                     if (numnotnull) {
                   1580:                         var possgrace = total+':'+frac+':'+grad;   
                   1581:                         if (patternGrace.test(possgrace)) {
                   1582:                             document.parmform.elements[i].value = possgrace;
                   1583:                             if (document.parmform.elements['set_'+identifier].value) {
                   1584:                                 document.parmform.elements['set_'+identifier].value += ',';
                   1585:                             }
                   1586:                             document.parmform.elements['set_'+identifier].value += document.parmform.elements[i].value;
                   1587:                         } else {
                   1588:                             if (frac == '') {
                   1589:                                 alert('Grace Period Past-Due: enter partial credit (number between 0 and 1.0).');
                   1590:                                 return false;
                   1591:                             } else {
                   1592:                                 alert('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.');
                   1593:                                 return false;
                   1594:                             }
                   1595:                         }
1.622     raeburn  1596:                     }
1.549     raeburn  1597:                 }
                   1598:             }
                   1599:         }
                   1600:     }
                   1601:     return true;
                   1602: }
                   1603: 
1.597     raeburn  1604: function isRadioSet(name,expected) {
                   1605:     var menuitems = document.getElementsByName(name);
                   1606:     var radioLength = menuitems.length;
                   1607:     result = false;
                   1608:     if (radioLength  > 1) {
                   1609:         for (var j=0; j<radioLength; j++) {
                   1610:             if (menuitems[j].checked) {
                   1611:                 if (menuitems[j].value == expected) {
                   1612:                     result = true;
                   1613:                     break;
                   1614:                 }
                   1615:             }
                   1616:         }
                   1617:     }
                   1618:     return result;
                   1619: }
                   1620: 
1.549     raeburn  1621: ENDSCRIPT
                   1622: }
                   1623: 
1.561     damieng  1624: # Javascript initialization, for overview mode
1.549     raeburn  1625: sub ipacc_boxes_js  {
                   1626:     my $remove = &mt('Remove');
                   1627:     return <<"END";
                   1628: \$(document).ready(function() {
                   1629:     var wrapper         = \$(".LC_string_ipacc_wrap");
                   1630:     var add_button      = \$(".LC_add_ipacc_button");
                   1631:     var ipaccRegExp     = /^LC_string_ipacc_/;
                   1632: 
                   1633:     \$(add_button).click(function(e){
                   1634:         e.preventDefault();
                   1635:         var identifier = \$(this).closest("div").attr("id");
                   1636:         identifier = identifier.replace(ipaccRegExp,'');
1.551     raeburn  1637:         \$(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  1638:     });
                   1639: 
                   1640:     \$(wrapper).delegate(".LC_remove_ipacc","click", function(e){
                   1641:         e.preventDefault(); \$(this).closest("div").remove();
                   1642:     })
                   1643: });
                   1644: 
                   1645: 
                   1646: END
                   1647: }
                   1648: 
1.622     raeburn  1649: sub grace_js {
                   1650:     my %lt = &grace_titles();
                   1651:     &js_escape(\%lt);
                   1652:     my $overdue = '<fieldset class="LC_grace"><legend>'.$lt{'sinc'}.'</legend>';
1.623     raeburn  1653:     foreach my $which (['weeks', 604800, 52],
                   1654:                        ['days', 86400, 6],
1.622     raeburn  1655:                        ['hours', 3600, 23],
1.623     raeburn  1656:                        ['minutes', 60, 59]) {
1.622     raeburn  1657:         my ($name, $factor, $max) = @{ $which };
                   1658:         my %select = ((map {$_ => $_} (0..$max)),
                   1659:                       'select_form_order' => [0..$max]);
1.623     raeburn  1660:         unshift(@{$select{'select_form_order'}},'');
                   1661:         $select{''} = '';
1.622     raeburn  1662:         my $selector = &Apache::loncommon::select_form('',$name."_'+identifier+'",
                   1663:                                                        \%select);
                   1664:         $selector =~ s/([\r\n\f]+)//g;
                   1665:         $overdue .= $selector.'&nbsp;'.$lt{$name}.('&nbsp;'x2).' ';
                   1666:     }
                   1667:     $overdue .= '</fieldset>';
                   1668:     return <<"END";
                   1669: \$(document).ready(function() {
                   1670:     var wrapper         = \$(".LC_string_grace_wrap");
                   1671:     var add_button      = \$(".LC_add_grace_button");
                   1672:     var graceRegExp     = /^LC_string_grace_/;
                   1673: 
                   1674:     \$(add_button).click(function(e){
                   1675:         e.preventDefault();
                   1676:         var identifier = \$(this).closest("div").attr("id");
                   1677:         identifier = identifier.replace(graceRegExp,'');
1.623     raeburn  1678:         \$(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  1679:     });
                   1680: 
                   1681:     \$(wrapper).delegate(".LC_remove_grace","click", function(e){
                   1682:         e.preventDefault(); \$(this).closest("div").remove();
                   1683:     })
                   1684: });
                   1685: 
                   1686: 
                   1687: END
                   1688: }
                   1689: 
1.561     damieng  1690: # Javascript function toggleSecret, for overview mode.
1.558     raeburn  1691: sub done_proctor_js {
1.611     raeburn  1692:     my $defaultdone = &mt('Done');
                   1693:     &js_escape(\$defaultdone);
1.558     raeburn  1694:     return <<"END";
                   1695: function toggleSecret(form,radio,key) {
                   1696:     var radios = form[radio+key];
                   1697:     if (radios.length) {
                   1698:         for (var i=0; i<radios.length; i++) {
                   1699:             if (radios[i].checked) {
                   1700:                 if (radios[i].value == '_done_proctor') {
                   1701:                     if (document.getElementById('done_'+key+'_proctorkey')) {
                   1702:                         document.getElementById('done_'+key+'_proctorkey').type='text';
                   1703:                     }
                   1704:                 } else {
                   1705:                     if (document.getElementById('done_'+key+'_proctorkey')) {
                   1706:                         document.getElementById('done_'+key+'_proctorkey').type='hidden';
                   1707:                         document.getElementById('done_'+key+'_proctorkey').value='';
                   1708:                     }
                   1709:                 }
1.611     raeburn  1710:                 if (document.getElementById('done_'+key+'_buttontext')) {
                   1711:                     if (radios[i].value == '') {
                   1712:                         document.getElementById('done_'+key+'_buttontext').value = '';
                   1713:                     } else {
                   1714:                         if (document.getElementById('done_'+key+'_buttontext').value == '') {
                   1715:                             document.getElementById('done_'+key+'_buttontext').value = '$defaultdone';
                   1716:                         }
                   1717:                     }
                   1718:                 }
1.558     raeburn  1719:             }
                   1720:         }
                   1721:     }
                   1722: }
                   1723: END
                   1724: 
                   1725: }
                   1726: 
1.588     raeburn  1727: # Javascript function toggle
                   1728: sub deeplink_js {
                   1729:     return <<"END";
                   1730: function toggleDeepLink(form,item,key) {
                   1731:     var radios = form['deeplink_'+item+'_'+key];
                   1732:     if (radios.length) {
                   1733:         var keybox;
                   1734:         if (document.getElementById('deeplink_key_'+item+'_'+key)) {
                   1735:             keybox = document.getElementById('deeplink_key_'+item+'_'+key);
                   1736:         }
1.601     raeburn  1737:         var divoptions = new Array();
                   1738:         if (item == 'protect') {
                   1739:             divoptions = ['ltic','ltid'];
1.597     raeburn  1740:         } else {
                   1741:             if (item == 'menus') {
1.601     raeburn  1742:                 divoptions = ['colls'];
1.597     raeburn  1743:             }
                   1744:         }
1.601     raeburn  1745:         var seldivs = new Array();
                   1746:         if ((item == 'protect') || (item == 'menus')) {
                   1747:             for (var i=0; i<divoptions.length; i++) {
                   1748:                 if (document.getElementById('deeplinkdiv_'+divoptions[i]+'_'+item+'_'+key)) {
                   1749:                     seldivs[i] = document.getElementById('deeplinkdiv_'+divoptions[i]+'_'+item+'_'+key);
                   1750:                 } else {
                   1751:                     seldivs[i] = '';
                   1752:                 }
                   1753:             }
1.588     raeburn  1754:         }
                   1755:         for (var i=0; i<radios.length; i++) {
                   1756:             if (radios[i].checked) {
1.601     raeburn  1757:                 if ((item == 'protect') || (item == 'menus')) {
                   1758:                     for (var j=0; j<seldivs.length; j++) {
                   1759:                         if (radios[i].value == divoptions[j]) {
                   1760:                             if (seldivs[j] != '') {
                   1761:                                 seldivs[j].style.display = 'inline-block';
                   1762:                             }
                   1763:                             if (item == 'protect') {
                   1764:                                 keybox.type = 'hidden';
                   1765:                                 keybox.value = '';
                   1766:                             }
                   1767:                         } else {
                   1768:                             if (seldivs[j] != '') {
                   1769:                                 seldivs[j].style.display = 'none';
                   1770:                                 form['deeplink_'+divoptions[j]+'_'+key].selectedIndex = 0;
                   1771:                             }
                   1772:                         }
1.597     raeburn  1773:                     }
1.601     raeburn  1774:                     if (item == 'protect') {
1.597     raeburn  1775:                         if (radios[i].value == 'key') {
                   1776:                             keybox.type = 'text';
                   1777:                         } else {
                   1778:                             keybox.type = 'hidden';
                   1779:                         }
1.588     raeburn  1780:                     }
1.616     raeburn  1781:                 } else if (item == 'exit') {
                   1782:                     if (document.getElementById('deeplinkdiv_'+item+'_'+key)) {
                   1783:                         if (radios[i].value == 'no') {
                   1784:                             document.getElementById('deeplinkdiv_'+item+'_'+key).style.display = 'none';          
                   1785:                             if (document.getElementById('deeplink_exittext_'+key)) {
                   1786:                                 if (document.getElementById('deeplink_exittext_'+key).value != '') {
                   1787:                                     document.getElementById('deeplink_exittext_'+key).value = '';    
                   1788:                                 }
                   1789:                             }
                   1790:                         } else {
                   1791:                             document.getElementById('deeplinkdiv_'+item+'_'+key).style.display = 'inline-block';
                   1792:                             if (document.getElementById('deeplink_exittext_'+key)) {
                   1793:                                 if (document.getElementById('deeplink_exittext_'+key).value == '') {
                   1794:                                     document.getElementById('deeplink_exittext_'+key).value = 'Exit Tool';
                   1795:                                 }
                   1796:                             }
                   1797:                         }
                   1798:                     }
1.588     raeburn  1799:                 }
                   1800:             }
                   1801:         }
                   1802:     }
                   1803: }
                   1804: END
                   1805: 
                   1806: }
                   1807: 
1.561     damieng  1808: # Prints HTML page start for table mode.
                   1809: # @param {Apache2::RequestRec} $r - the Apache request
                   1810: # @param {string} $psymb - resource symb
                   1811: # @param {string} $crstype - course type (Community / Course / Placement Test)
1.280     albertel 1812: sub startpage {
1.531     raeburn  1813:     my ($r,$psymb,$crstype) = @_;
1.281     albertel 1814: 
1.515     raeburn  1815:     my %loaditems = (
                   1816:                       'onload'   => "group_or_section('cgroup')",
                   1817:                     );
                   1818:     if (!$psymb) {
1.523     raeburn  1819:         $loaditems{'onload'} = "showHide_courseContent(); group_or_section('cgroup'); resize_scrollbox('mapmenuscroll','1','1');";
1.515     raeburn  1820:     }
1.280     albertel 1821: 
1.560     damieng  1822:     if ((($env{'form.command'} eq 'set') && ($env{'form.url'}) &&
                   1823:             (!$env{'form.dis'})) || ($env{'form.symb'})) {
                   1824:         &Apache::lonhtmlcommon::add_breadcrumb({help=>'Problem_Parameters',
                   1825:             text=>"Problem Parameters"});
1.414     droeschl 1826:     } else {
1.560     damieng  1827:         &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=settable',
                   1828:             text=>"Table Mode",
                   1829:             help => 'Course_Setting_Parameters'});
1.414     droeschl 1830:     }
1.523     raeburn  1831:     my $js = &page_js().'
                   1832: <script type="text/javascript">
                   1833: // <![CDATA[
                   1834: '.
                   1835:             &Apache::lonhtmlcommon::resize_scrollbox_js('params').'
                   1836: // ]]>
                   1837: </script>
                   1838: ';
1.446     bisitz   1839:     my $start_page =
1.523     raeburn  1840:         &Apache::loncommon::start_page('Set/Modify Course Parameters',$js,
                   1841:                                        {'add_entries' => \%loaditems,});
1.446     bisitz   1842:     my $breadcrumbs =
1.473     amueller 1843:     &Apache::lonhtmlcommon::breadcrumbs('Table Mode Parameter Setting','Table_Mode');
1.506     www      1844:     my $escfilter=&Apache::lonhtmlcommon::entity_encode($env{'form.filter'});
                   1845:     my $escpart=&Apache::lonhtmlcommon::entity_encode($env{'form.part'});
1.507     www      1846:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  1847:     &startSettingsScreen($r,'parmset',$crstype);
1.280     albertel 1848:     $r->print(<<ENDHEAD);
1.193     albertel 1849: <form method="post" action="/adm/parmset?action=settable" name="parmform">
1.419     bisitz   1850: <input type="hidden" value="" name="pres_value" />
                   1851: <input type="hidden" value="" name="pres_type" />
                   1852: <input type="hidden" value="" name="pres_marker" />
                   1853: <input type="hidden" value="1" name="prevvisit" />
1.506     www      1854: <input type="hidden" value="$escfilter" name="filter" />
                   1855: <input type="hidden" value="$escpart" name="part" />
1.44      albertel 1856: ENDHEAD
                   1857: }
                   1858: 
1.209     www      1859: 
1.561     damieng  1860: # Prints a row for table mode (except for the tr start).
                   1861: # Every time a hash reference is passed, a single entry is used, so print_row
                   1862: # could just use these values, but why make it simple when it can be complicated ?
                   1863: #
                   1864: # @param {Apache2::RequestRec} $r - the Apache request
                   1865: # @param {string} $which - parameter key ('parameter_'.part.'_'.name)
                   1866: # @param {hash reference} $part - parameter key -> parameter part (can be problem part.'_'.response id for response parameters)
                   1867: # @param {hash reference} $name - parameter key -> parameter name
1.566     damieng  1868: # @param {hash reference} $symbp - map pc or resource/map id -> map src.'___(all)' or resource symb
1.561     damieng  1869: # @param {string} $rid - resource id
                   1870: # @param {hash reference} $default - parameter key -> resource parameter default value
                   1871: # @param {hash reference} $defaulttype - parameter key -> resource parameter default type
                   1872: # @param {hash reference} $display - parameter key -> full title for the parameter
                   1873: # @param {string} $defbgone - user level and other levels background color
                   1874: # @param {string} $defbgtwo - section level background color, also used for part number
                   1875: # @param {string} $defbgthree - group level background color
                   1876: # @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general')
                   1877: # @param {string} $uname - user name
                   1878: # @param {string} $udom - user domain
                   1879: # @param {string} $csec - section name
                   1880: # @param {string} $cgroup - group name
                   1881: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   1882: # @param {boolean} $noeditgrp - true if no edit is allowed for group level parameters
1.582     raeburn  1883: # @param {boolean} $readonly - true if no editing allowed.
                   1884: # @param {array reference} - $recurseup - list of maps containing current one, ending at top-level.
                   1885: # @param {hash reference} - $maptitles - - hash map id or src -> map title 
                   1886: # @param {hash reference} - $allmaps_inverted - hash map src -> map pc
                   1887: # @param {scalar reference} - $reclinks - number of "parameter in effect" cells with link to map where recursive param was set 
1.44      albertel 1888: sub print_row {
1.201     www      1889:     my ($r,$which,$part,$name,$symbp,$rid,$default,$defaulttype,$display,$defbgone,
1.568     raeburn  1890:     $defbgtwo,$defbgthree,$parmlev,$uname,$udom,$csec,$cgroup,$usersgroups,$noeditgrp,
1.582     raeburn  1891:     $readonly,$recurseup,$maptitles,$allmaps_inverted,$reclinks)=@_;
1.275     raeburn  1892:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   1893:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   1894:     my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
1.582     raeburn  1895:     my $numlinks = 0;
1.553     raeburn  1896: 
1.560     damieng  1897:     # get the values for the parameter in cascading order
                   1898:     # empty levels will remain empty
1.44      albertel 1899:     my ($result,@outpar)=&parmval($$part{$which}.'.'.$$name{$which},
1.473     amueller 1900:       $rid,$$default{$which},$uname,$udom,$csec,$cgroup,$courseopt);
1.560     damieng  1901:     # get the type for the parameters
                   1902:     # problem: these may not be set for all levels
1.66      www      1903:     my ($typeresult,@typeoutpar)=&parmval($$part{$which}.'.'.
1.275     raeburn  1904:                                           $$name{$which}.'.type',$rid,
1.473     amueller 1905:          $$defaulttype{$which},$uname,$udom,$csec,$cgroup,$courseopt);
1.560     damieng  1906:     # cascade down manually
1.182     albertel 1907:     my $cascadetype=$$defaulttype{$which};
1.556     raeburn  1908:     for (my $i=18;$i>0;$i--) {
1.560     damieng  1909:         if ($typeoutpar[$i]) {
1.66      www      1910:             $cascadetype=$typeoutpar[$i];
1.560     damieng  1911:         } else {
1.66      www      1912:             $typeoutpar[$i]=$cascadetype;
                   1913:         }
                   1914:     }
1.57      albertel 1915:     my $parm=$$display{$which};
                   1916: 
1.203     www      1917:     if ($parmlev eq 'full') {
1.419     bisitz   1918:         $r->print('<td style="background-color:'.$defbgtwo.';" align="center">'
1.506     www      1919:                   .($$part{$which} eq '0'?'0 ('.&mt('default').')':$$part{$which}).'</td>');
1.433     raeburn  1920:     } else {
1.57      albertel 1921:         $parm=~s|\[.*\]\s||g;
                   1922:     }
1.231     www      1923:     my $automatic=&rulescache(($which=~/\_([^\_]+)$/)[0].'_triggers');
                   1924:     if ($automatic) {
1.560     damieng  1925:         $parm.='<span class="LC_warning"><br />'.&mt('Automatically sets').' '.join(', ',split(/\:/,$automatic)).'</span>';
1.231     www      1926:     }
1.619     raeburn  1927:     my $advice;
                   1928:     if ((ref($name) eq 'HASH') && ($name->{$which} eq 'mapalias') &&
                   1929:         (ref($symbp) eq 'HASH') && ($parmlev eq 'full')) {
                   1930:         if ($symbp->{$rid} =~ m{^uploaded/}) {
                   1931:             if ($result == 14) {
                   1932:                 $advice = &mt('Use Course Editor to modify this.');
                   1933:             } else {
                   1934:                 $advice = &mt('Use Course Editor to set this.');
                   1935:             }
                   1936:         } else {
                   1937:             if ($result == 14) {
                   1938:                 $advice = &mt('Use Resource Assembly Tool to modify this.');
                   1939:             } else {
                   1940:                 $advice = &mt('Use Resource Assembly Tool to set this.');
                   1941:             }
                   1942:         }
                   1943:         $parm .= '<br /><span class="LC_fontsize_small LC_cusr_emph">'.$advice.'</span>';
                   1944:     }
1.427     bisitz   1945:     $r->print('<td>'.$parm.'</td>');
1.446     bisitz   1946: 
1.44      albertel 1947:     my $thismarker=$which;
                   1948:     $thismarker=~s/^parameter\_//;
                   1949:     my $mprefix=$rid.'&'.$thismarker.'&';
1.582     raeburn  1950:     my ($parmname)=($thismarker=~/\_([^\_]+)$/);
                   1951:     my ($othergrp,$grp_parm,$controlgrp,$effective_parm,$effparm_rec,$effparm_level,
1.588     raeburn  1952:         $eff_groupparm,$recurse_check,$recursinfo,$extra);
1.582     raeburn  1953:     if ((ref($recurseup) eq 'ARRAY') && (@{$recurseup} > 0)) {
                   1954:         if ($result eq '') {
                   1955:             $recurse_check = 1;
                   1956:         } elsif (($uname ne '') && ($result > 3)) {
                   1957:             $recurse_check = 1;
                   1958:         } elsif (($cgroup ne '') && ($result > 7)) {
                   1959:             $recurse_check = 1;
                   1960:         } elsif (($csec ne '') && ($result > 11)) {
                   1961:             $recurse_check = 1;
                   1962:         } elsif ($result > 17) {
                   1963:             $recurse_check = 1;
                   1964:         }
                   1965:         if ($recurse_check) {
                   1966:             my $what = $$part{$which}.'.'.$$name{$which};
                   1967:             my $prefix;
                   1968:             if (($uname ne '') && ($udom ne '')) {
                   1969:                 my $useropt = &Apache::lonnet::get_userresdata($uname,$udom);
                   1970:                 $prefix = $env{'request.course.id'};
                   1971:                 $recursinfo = &get_recursive($recurseup,$useropt,$what,$prefix);
                   1972:                 if (ref($recursinfo) eq 'ARRAY') {
                   1973:                     $effparm_rec = 1;
                   1974:                     $effparm_level = &mt('user: [_1]',$uname);
                   1975:                 }
                   1976:             }
                   1977:             if (($cgroup ne '') && (!$effparm_rec)) {
                   1978:                 $prefix = $env{'request.course.id'}.'.['.$cgroup.']';
                   1979:                 $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix);
                   1980:                 if (ref($recursinfo) eq 'ARRAY') {
                   1981:                     $effparm_rec = 1;
                   1982:                     $effparm_level = &mt('group: [_1]',$cgroup);
                   1983:                 }
                   1984:             }
                   1985:             if (($csec ne '') && (!$effparm_rec)) {
                   1986:                 $prefix = $env{'request.course.id'}.'.['.$csec.']';
                   1987:                 $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix);
                   1988:                 if (ref($recursinfo) eq 'ARRAY') {
                   1989:                     $effparm_rec = 1;
                   1990:                     $effparm_level = &mt('section: [_1]',$csec);
                   1991:                 }
                   1992:             }
                   1993:             if (!$effparm_rec) {
                   1994:                 $prefix = $env{'request.course.id'};
                   1995:                 $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix); 
                   1996:                 if (ref($recursinfo) eq 'ARRAY') {
                   1997:                     $effparm_rec = 1;
                   1998:                 }
                   1999:             }
                   2000:         }
                   2001:     }
                   2002:     if ((!$effparm_rec) && ($result == 17 || $result == 11 || $result == 7 || $result == 3)) {
                   2003:         $effparm_rec = 1;
                   2004:     }
                   2005:     if ((!$effparm_rec) && 
                   2006:         (($$name{$which} eq 'encrypturl') || ($$name{$which} eq 'hiddenresource')) && 
                   2007:         ($result == 16 || $result == 10 || $result == 6 || $result == 2)) {
1.578     raeburn  2008:         $effparm_rec = 1;
                   2009:     }
1.588     raeburn  2010:     if ($parmname eq 'deeplink') {
1.601     raeburn  2011:         my ($domltistr,$crsltistr);
1.588     raeburn  2012:         my %lti =
                   2013:             &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'},
1.604     raeburn  2014:                                             'linkprot');
1.601     raeburn  2015:         if (keys(%lti)) {
                   2016:             foreach my $item (sort { $a <=> $b }  (keys(%lti))) {
1.604     raeburn  2017:                 if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) {
                   2018:                     $domltistr .= $item.':'.&escape(&escape($lti{$item}{'name'})).',';
1.588     raeburn  2019:                 }
                   2020:             }
1.601     raeburn  2021:             $domltistr =~ s/,$//;
                   2022:             if ($domltistr) {
                   2023:                 $extra = 'ltid_'.$domltistr;
                   2024:             }
1.588     raeburn  2025:         }
1.620     raeburn  2026:         my %courselti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider');
1.601     raeburn  2027:         if (keys(%courselti)) {
                   2028:             foreach my $item (sort { $a <=> $b } keys(%courselti)) {
                   2029:                 if (($item =~ /^\d+$/) && (ref($courselti{$item}) eq 'HASH')) {
                   2030:                     $crsltistr .= $item.':'.&escape(&escape($courselti{$item}{'name'})).',';
                   2031:                 }
                   2032:             }
                   2033:             $crsltistr =~ s/,$//;
                   2034:             if ($crsltistr) {
                   2035:                 if ($extra) {
                   2036:                     $extra .= '&';
                   2037:                 }
                   2038:                 $extra .= 'ltic_'.$crsltistr;
1.588     raeburn  2039:             }
                   2040:         }
1.597     raeburn  2041:         if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) {
                   2042:             my @colls;
                   2043:             foreach my $item (split(/;/,$env{'course.'.$env{'request.course.id'}.'.menucollections'})) {
                   2044:                 my ($num,$value) = split(/\%/,$item);
                   2045:                 if ($num =~ /^\d+$/) {
                   2046:                     push(@colls,$num);
                   2047:                 }
                   2048:             }
                   2049:             if (@colls) {
                   2050:                 if ($extra) {
                   2051:                     $extra .= '&';
                   2052:                 }
                   2053:                 $extra .= 'menus_'.join(',',@colls);
                   2054:             }
                   2055:         }
1.588     raeburn  2056:     }
1.57      albertel 2057:     if ($parmlev eq 'general') {
                   2058:         if ($uname) {
1.588     raeburn  2059:             &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.269     raeburn  2060:         } elsif ($cgroup) {
1.588     raeburn  2061:             &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra);
1.57      albertel 2062:         } elsif ($csec) {
1.588     raeburn  2063:             &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.57      albertel 2064:         } else {
1.588     raeburn  2065:             &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.57      albertel 2066:         }
                   2067:     } elsif ($parmlev eq 'map') {
                   2068:         if ($uname) {
1.588     raeburn  2069:             &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
1.269     raeburn  2070:         } elsif ($cgroup) {
1.588     raeburn  2071:             &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra);
1.57      albertel 2072:         } elsif ($csec) {
1.588     raeburn  2073:             &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
1.57      albertel 2074:         } else {
1.588     raeburn  2075:             &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
1.57      albertel 2076:         }
                   2077:     } else {
1.275     raeburn  2078:         if ($uname) {
                   2079:             if (@{$usersgroups} > 1) {
1.582     raeburn  2080:                 (my $coursereply,$othergrp,$grp_parm,$controlgrp,my $grp_is_rec) =
1.580     raeburn  2081:                     &check_other_groups($$part{$which}.'.'.$$name{$which},
1.275     raeburn  2082:                        $rid,$cgroup,$defbgone,$usersgroups,$result,$courseopt);
1.582     raeburn  2083:                 if (($coursereply) && ($result > 4)) {
1.275     raeburn  2084:                     if (defined($controlgrp)) {
                   2085:                         if ($cgroup ne $controlgrp) {
1.582     raeburn  2086:                             $eff_groupparm = $grp_parm;
                   2087:                             undef($result);
                   2088:                             undef($effparm_rec);
                   2089:                             if ($grp_is_rec) {
                   2090:                                  $effparm_rec = 1;
                   2091:                             }
1.275     raeburn  2092:                         }
                   2093:                     }
                   2094:                 }
                   2095:             }
                   2096:         }
1.57      albertel 2097: 
1.588     raeburn  2098:         &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2099:         &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
                   2100:         &print_td($r,15,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2101:         &print_td($r,14,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2102:         &print_td($r,13,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.548     raeburn  2103: 
                   2104:         if ($csec) {
1.588     raeburn  2105:             &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2106:             &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
                   2107:             &print_td($r,9,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.548     raeburn  2108:         }
1.269     raeburn  2109: 
                   2110:         if ($cgroup) {
1.588     raeburn  2111:             &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra);
                   2112:             &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra);
                   2113:             &print_td($r,5,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp.$readonly,'',$extra);
1.269     raeburn  2114:         }
1.446     bisitz   2115: 
1.548     raeburn  2116:         if ($uname) {
1.275     raeburn  2117:             if ($othergrp) {
                   2118:                 $r->print($othergrp);
                   2119:             }
1.588     raeburn  2120:             &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2121:             &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
                   2122:             &print_td($r,1,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.548     raeburn  2123:         }
1.57      albertel 2124:     } # end of $parmlev if/else
1.582     raeburn  2125:     if (ref($recursinfo) eq 'ARRAY') {
                   2126:         my $rectitle = &mt('recursive');
                   2127:         if ((ref($maptitles) eq 'HASH') && (exists($maptitles->{$recursinfo->[2]}))) {
                   2128:             if ((ref($allmaps_inverted) eq 'HASH') && (exists($allmaps_inverted->{$recursinfo->[2]}))) {
                   2129:                 $rectitle = &mt('set in: [_1]','"'.
                   2130:                                 '<a href="javascript:pjumprec('."'".$allmaps_inverted->{$recursinfo->[2]}."',".
                   2131:                                                               "'$parmname','$$part{$which}'".');">'.
                   2132:                                 $maptitles->{$recursinfo->[2]}.'</a>"');
                   2133:               
                   2134:                 $numlinks ++;
                   2135:             }
                   2136:         }
                   2137:         my ($parmname)=($thismarker=~/\_([^\_]+)$/);
1.593     raeburn  2138:         $effective_parm = &valout($recursinfo->[0],$recursinfo->[1]);
1.582     raeburn  2139:         $r->print('<td style="background-color:#CCCCFF;" align="center">'.$effective_parm.
                   2140:                   '<br /><span class="LC_parm_recursive">'.$rectitle.'&nbsp;'.
                   2141:                   $effparm_level.'</span></td>');
                   2142:     } else {
                   2143:         if ($result) {
1.593     raeburn  2144:             $effective_parm = &valout($outpar[$result],$typeoutpar[$result]);
1.582     raeburn  2145:         }
                   2146:         if ($eff_groupparm) {
                   2147:             $effective_parm = $eff_groupparm;
                   2148:         }
                   2149:         $r->print('<td style="background-color:#CCCCFF;" align="center">'.$effective_parm.
                   2150:                   ($effparm_rec?'<br /><span class="LC_parm_recursive">'.&mt('recursive').
                   2151:                                 '</span>':'').'</td>');
                   2152:     }
1.203     www      2153:     if ($parmlev eq 'full') {
1.136     albertel 2154:         my $sessionval=&Apache::lonnet::EXT('resource.'.$$part{$which}.
1.201     www      2155:                                         '.'.$$name{$which},$$symbp{$rid});
1.136     albertel 2156:         my $sessionvaltype=$typeoutpar[$result];
1.560     damieng  2157:         if (!defined($sessionvaltype)) {
                   2158:             $sessionvaltype=$$defaulttype{$which};
                   2159:         }
1.419     bisitz   2160:         $r->print('<td style="background-color:#999999;" align="center"><font color="#FFFFFF">'.
1.593     raeburn  2161:                   &valout($sessionval,$sessionvaltype).'&nbsp;'.
1.57      albertel 2162:                   '</font></td>');
1.136     albertel 2163:     }
1.44      albertel 2164:     $r->print('</tr>');
1.57      albertel 2165:     $r->print("\n");
1.582     raeburn  2166:     if (($numlinks) && (ref($reclinks))) {
                   2167:         $$reclinks = $numlinks;
                   2168:     }
1.44      albertel 2169: }
1.59      matthew  2170: 
1.561     damieng  2171: # Prints a cell for table mode.
                   2172: #
                   2173: # FIXME: some of these parameter names are uninspired ($which and $value)
                   2174: # Also, it would make more sense to pass the display for this cell rather
                   2175: # than the full display hash and the key to use.
                   2176: #
                   2177: # @param {Apache2::RequestRec} $r - the Apache request
                   2178: # @param {integer} $which - level
                   2179: # @param {string} $defbg - cell background color
                   2180: # @param {integer} $result - the most specific level that is defined for that parameter
                   2181: # @param {array reference} $outpar - array level -> parameter value (when defined)
                   2182: # @param {string} $mprefix - resource id.'&'.part.'_'.parameter name.'&'
                   2183: # @param {string} $value - parameter key ('parameter_'.part.'_'.name)
                   2184: # @param {array reference} $typeoutpar - array level -> parameter type (when defined)
                   2185: # @param {hash reference} $display - parameter key -> full title for the parameter
                   2186: # @param {boolean} $noeditgrp - true if no edit is allowed for group level parameters
1.568     raeburn  2187: # @param {boolean} $readonly -true if editing not allowed.
1.588     raeburn  2188: # @param {boolean} $ismaplevel - true if level is for a map.
1.597     raeburn  2189: # @param {string} $extra - extra information to pass to plink.
1.44      albertel 2190: sub print_td {
1.578     raeburn  2191:     my ($r,$which,$defbg,$result,$outpar,$mprefix,$value,$typeoutpar,$display,
1.588     raeburn  2192:         $noeditgrp,$readonly,$ismaplevel,$extra)=@_;
1.578     raeburn  2193:     my ($ineffect,$recursive,$currval,$currtype,$currlevel);
                   2194:     $ineffect = 0;
                   2195:     $currval = $$outpar[$which];
                   2196:     $currtype = $$typeoutpar[$which];
                   2197:     $currlevel = $which;
                   2198:     if (($result) && ($result == $which)) {
                   2199:         $ineffect = 1;
                   2200:     } 
                   2201:     if ($ismaplevel) {
                   2202:         if ($mprefix =~ /(hiddenresource|encrypturl)\&/) {
                   2203:             if (($result) && ($result == $which)) {
                   2204:                 $recursive = 1;
                   2205:             }
                   2206:         } elsif ($$outpar[$which+1] ne '') {
                   2207:             $recursive = 1;
                   2208:             $currlevel = $which+1;
                   2209:             $currval = $$outpar[$currlevel];
                   2210:             $currtype = $$typeoutpar[$currlevel];
                   2211:             if (($result) && ($result == $currlevel)) {
                   2212:                 $ineffect = 1;
                   2213:             }
                   2214:         }
                   2215:     }
                   2216:     $r->print('<td style="background-color:'.($ineffect?'#AAFFAA':$defbg).
1.419     bisitz   2217:               ';" align="center">');
1.437     raeburn  2218:     my $nolink = 0;
1.568     raeburn  2219:     if ($readonly) {
1.552     raeburn  2220:         $nolink = 1;
1.568     raeburn  2221:     } else { 
1.578     raeburn  2222:         if ($which == 14 || $which == 15 || $mprefix =~ /mapalias\&$/) {
1.553     raeburn  2223:             $nolink = 1;
1.568     raeburn  2224:         } elsif (($env{'request.course.sec'} ne '') && ($which > 12)) {
1.533     raeburn  2225:             $nolink = 1;
1.568     raeburn  2226:         } elsif ($which == 5 || $which ==  6 || $which == 7 || $which == 8) {
                   2227:             if ($noeditgrp) {
                   2228:                 $nolink = 1;
                   2229:             }
                   2230:         } elsif ($mprefix =~ /availablestudent\&$/) {
1.599     raeburn  2231:             $nolink = 1;
1.568     raeburn  2232:         } elsif ($mprefix =~ /examcode\&$/) {
                   2233:             unless ($which == 2) {
                   2234:                 $nolink = 1;
                   2235:             }
1.533     raeburn  2236:         }
1.437     raeburn  2237:     }
                   2238:     if ($nolink) {
1.577     raeburn  2239:         my ($parmname)=((split(/\&/,$mprefix))[1]=~/\_([^\_]+)$/);
1.593     raeburn  2240:         $r->print(&valout($currval,$currtype));
1.114     www      2241:     } else {
1.578     raeburn  2242:         $r->print(&plink($currtype,
                   2243:                          $$display{$value},$currval,
1.588     raeburn  2244:                          $mprefix.$currlevel,'parmform.pres','psub',$recursive,
                   2245:                          $extra));
1.114     www      2246:     }
                   2247:     $r->print('</td>'."\n");
1.57      albertel 2248: }
                   2249: 
1.561     damieng  2250: # Returns HTML and other info for the cell added when a user is selected
                   2251: # and that user is in several groups. This is the cell with the title "Control by other group".
                   2252: #
                   2253: # @param {string} $what - parameter part.'.'.parameter name
                   2254: # @param {string} $rid - resource id
                   2255: # @param {string} $cgroup - group name
                   2256: # @param {string} $defbg - cell background color
                   2257: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   2258: # @param {integer} $result - level
                   2259: # @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db)
1.582     raeburn  2260: # @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  2261: sub check_other_groups {
                   2262:     my ($what,$rid,$cgroup,$defbg,$usersgroups,$result,$courseopt) = @_;
1.275     raeburn  2263:     my $courseid = $env{'request.course.id'};
                   2264:     my $output;
                   2265:     my $symb = &symbcache($rid);
                   2266:     my $symbparm=$symb.'.'.$what;
                   2267:     my $map=(&Apache::lonnet::decode_symb($symb))[0];
1.556     raeburn  2268:     my $recurseparm=$map.'___(rec).'.$what; 
1.275     raeburn  2269:     my $mapparm=$map.'___(all).'.$what;
                   2270:     my ($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype) =
1.556     raeburn  2271:           &parm_control_group($courseid,$usersgroups,$symbparm,$mapparm,
                   2272:                               $recurseparm,$what,$courseopt);
1.275     raeburn  2273:     my $bgcolor = $defbg;
1.582     raeburn  2274:     my ($grp_parm,$grp_is_rec);
1.446     bisitz   2275:     if (($coursereply) && ($cgroup ne $resultgroup)) {
1.582     raeburn  2276:         my ($parmname) = ($what =~ /\.([^.]+)$/);
1.275     raeburn  2277:         if ($result > 3) {
1.419     bisitz   2278:             $bgcolor = '#AAFFAA';
1.275     raeburn  2279:         }
1.593     raeburn  2280:         $grp_parm = &valout($coursereply,$resulttype);
1.419     bisitz   2281:         $output = '<td style="background-color:'.$bgcolor.';" align="center">';
1.275     raeburn  2282:         if ($resultgroup && $resultlevel) {
1.582     raeburn  2283:             if ($resultlevel eq 'recursive') {
                   2284:                 $resultlevel = 'map/folder';
                   2285:                 $grp_is_rec = 1;
                   2286:             }
                   2287:             $output .= '<small><b>'.$resultgroup.'</b> ('.$resultlevel.'): </small>'.$grp_parm.
                   2288:                        ($grp_is_rec?'<span class="LC_parm_recursive">'.&mt('recursive').'</span>':'');
                   2289:              
1.275     raeburn  2290:         } else {
                   2291:             $output .= '&nbsp;';
                   2292:         }
                   2293:         $output .= '</td>';
                   2294:     } else {
1.419     bisitz   2295:         $output .= '<td style="background-color:'.$bgcolor.';">&nbsp;</td>';
1.275     raeburn  2296:     }
1.582     raeburn  2297:     return ($coursereply,$output,$grp_parm,$resultgroup,$grp_is_rec);
1.275     raeburn  2298: }
                   2299: 
1.561     damieng  2300: # Looks for a group with a defined parameter for given user and parameter.
1.580     raeburn  2301: # Used by check_other_groups.
1.561     damieng  2302: #
                   2303: # @param {string} $courseid - the course id
                   2304: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   2305: # @param {string} $symbparm - end of the course parameter hash key for the group resource level
                   2306: # @param {string} $mapparm - end of the course parameter hash key for the group map/folder level
                   2307: # @param {string} $recurseparm - end of the course parameter hash key for the group recursive level
                   2308: # @param {string} $what - parameter part.'.'.parameter name
                   2309: # @param {hash reference} $courseopt - course parameters hash
                   2310: # @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  2311: sub parm_control_group {
1.556     raeburn  2312:     my ($courseid,$usersgroups,$symbparm,$mapparm,$recurseparm,$what,$courseopt) = @_;
1.275     raeburn  2313:     my ($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype);
                   2314:     my $grpfound = 0;
1.556     raeburn  2315:     my @levels = ($symbparm,$mapparm,$recurseparm,$what);
                   2316:     my @levelnames = ('resource','map/folder','recursive','general');
1.275     raeburn  2317:     foreach my $group (@{$usersgroups}) {
                   2318:         if ($grpfound) { last; }
                   2319:         for (my $i=0; $i<@levels; $i++) {
                   2320:             my $item = $courseid.'.['.$group.'].'.$levels[$i];
                   2321:             if (defined($$courseopt{$item})) {
                   2322:                 $coursereply = $$courseopt{$item};
                   2323:                 $resultitem = $item;
                   2324:                 $resultgroup = $group;
                   2325:                 $resultlevel = $levelnames[$i];
                   2326:                 $resulttype = $$courseopt{$item.'.type'};
                   2327:                 $grpfound = 1;
                   2328:                 last;
                   2329:             }
                   2330:         }
                   2331:     }
                   2332:     return($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype);
                   2333: }
1.201     www      2334: 
1.63      bowersj2 2335: 
                   2336: 
1.562     damieng  2337: # Extracts lots of information about all of the the course's resources into a variety of hashes, using lonnavmaps and lonnet::metadata.
                   2338: # All the parameters are references and are filled by the sub.
                   2339: #
1.566     damieng  2340: # @param {array reference} $ids - resource and map ids
                   2341: # @param {hash reference} $typep - hash resource/map id -> resource type (file extension)
                   2342: # @param {hash reference} $keyp - hash resource/map id -> comma-separated list of parameter keys from lonnet::metadata
1.562     damieng  2343: # @param {hash reference} $allparms - hash parameter name -> parameter title
                   2344: # @param {hash reference} $allparts - hash parameter part -> part title (a parameter part can be problem part.'_'.response id for response parameters)
1.566     damieng  2345: # @param {hash reference} $allmaps - hash map pc -> map src
                   2346: # @param {hash reference} $mapp - hash map pc or resource/map id -> enclosing map src
                   2347: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' for a map or resource symb for a resource
                   2348: # @param {hash reference} $maptitles - hash map pc or src -> map title (this should really be two separate hashes)
                   2349: # @param {hash reference} $uris - hash resource/map id -> resource src
1.562     damieng  2350: # @param {hash reference} $keyorder - hash parameter key -> appearance rank for this parameter when looking through every resource and every parameter, starting at 100 (integer)
                   2351: # @param {hash reference} $defkeytype - hash parameter name -> parameter type
1.608     raeburn  2352: # @param {string} $pssymb - resource symb (when a single resource is selected)
1.63      bowersj2 2353: sub extractResourceInformation {
                   2354:     my $ids = shift;
                   2355:     my $typep = shift;
                   2356:     my $keyp = shift;
                   2357:     my $allparms = shift;
                   2358:     my $allparts = shift;
                   2359:     my $allmaps = shift;
                   2360:     my $mapp = shift;
                   2361:     my $symbp = shift;
1.82      www      2362:     my $maptitles=shift;
1.196     www      2363:     my $uris=shift;
1.210     www      2364:     my $keyorder=shift;
1.211     www      2365:     my $defkeytype=shift;
1.603     raeburn  2366:     my $pssymb=shift;
1.196     www      2367: 
1.210     www      2368:     my $keyordercnt=100;
1.63      bowersj2 2369: 
1.196     www      2370:     my $navmap = Apache::lonnavmaps::navmap->new();
1.603     raeburn  2371:     return unless(ref($navmap));
                   2372:     my @allres;
                   2373:     if ($pssymb ne '') {
                   2374:         my $res = $navmap->getBySymb($pssymb);
                   2375:         if (ref($res)) {
                   2376:             @allres = ($res);
                   2377:         }
                   2378:     }
                   2379:     if (!@allres) { 
                   2380:         @allres=$navmap->retrieveResources(undef,undef,1,undef,1);
                   2381:     }
1.196     www      2382:     foreach my $resource (@allres) {
1.480     amueller 2383:         my $id=$resource->id();
1.196     www      2384:         my ($mapid,$resid)=split(/\./,$id);
1.480     amueller 2385:         if ($mapid eq '0') { next; }
                   2386:         $$ids[$#$ids+1]=$id;
                   2387:         my $srcf=$resource->src();
                   2388:         $srcf=~/\.(\w+)$/;
                   2389:         $$typep{$id}=$1;
1.584     raeburn  2390:         my $toolsymb;
                   2391:         if ($srcf =~ /ext\.tool$/) {
                   2392:             $toolsymb = $resource->symb();
                   2393:         }
1.480     amueller 2394:         $$keyp{$id}='';
1.196     www      2395:         $$uris{$id}=$srcf;
1.512     foxr     2396: 
1.584     raeburn  2397:         foreach my $key (split(/\,/,&Apache::lonnet::metadata($srcf,'allpossiblekeys',$toolsymb))) {
1.480     amueller 2398:             next if ($key!~/^parameter_/);
1.363     albertel 2399: 
1.209     www      2400: # Hidden parameters
1.584     raeburn  2401:             next if (&Apache::lonnet::metadata($srcf,$key.'.hidden',$toolsymb) eq 'parm');
1.209     www      2402: #
                   2403: # allparms is a hash of parameter names
                   2404: #
1.584     raeburn  2405:             my $name=&Apache::lonnet::metadata($srcf,$key.'.name',$toolsymb);
1.480     amueller 2406:             if (!exists($$allparms{$name}) || $$allparms{$name} =~ m/^\s*$/ ) {
                   2407:                 my ($display,$parmdis);
                   2408:                 $display = &standard_parameter_names($name);
                   2409:                 if ($display eq '') {
1.584     raeburn  2410:                     $display= &Apache::lonnet::metadata($srcf,$key.'.display',$toolsymb);
1.480     amueller 2411:                     $parmdis = $display;
                   2412:                     $parmdis =~ s/\s*\[Part.*$//g;
                   2413:                 } else {
                   2414:                     $parmdis = &mt($display);
                   2415:                 }
                   2416:                 $$allparms{$name}=$parmdis;
                   2417:                 if (ref($defkeytype)) {
                   2418:                     $$defkeytype{$name}=
1.584     raeburn  2419:                     &Apache::lonnet::metadata($srcf,$key.'.type',$toolsymb);
1.480     amueller 2420:                 }
                   2421:             }
1.363     albertel 2422: 
1.209     www      2423: #
                   2424: # allparts is a hash of all parts
                   2425: #
1.584     raeburn  2426:             my $part= &Apache::lonnet::metadata($srcf,$key.'.part',$toolsymb);
1.480     amueller 2427:             $$allparts{$part} = &mt('Part: [_1]',$part);
1.209     www      2428: #
                   2429: # Remember all keys going with this resource
                   2430: #
1.480     amueller 2431:             if ($$keyp{$id}) {
                   2432:                 $$keyp{$id}.=','.$key;
                   2433:             } else {
                   2434:                 $$keyp{$id}=$key;
                   2435:             }   
1.210     www      2436: #
                   2437: # Put in order
1.446     bisitz   2438: #
1.480     amueller 2439:             unless ($$keyorder{$key}) {
                   2440:                 $$keyorder{$key}=$keyordercnt;
                   2441:                 $keyordercnt++;
                   2442:             }
1.473     amueller 2443:         }
                   2444: 
                   2445: 
1.480     amueller 2446:         if (!exists($$mapp{$mapid})) {
                   2447:             $$mapp{$id}=
                   2448:             &Apache::lonnet::declutter($resource->enclosing_map_src());
                   2449:             $$mapp{$mapid}=$$mapp{$id};
                   2450:             $$allmaps{$mapid}=$$mapp{$id};
                   2451:             if ($mapid eq '1') {
1.532     raeburn  2452:                 $$maptitles{$mapid}=&mt('Main Content');
1.480     amueller 2453:             } else {
                   2454:                 $$maptitles{$mapid}=&Apache::lonnet::gettitle($$mapp{$id});
                   2455:             }
                   2456:             $$maptitles{$$mapp{$id}}=$$maptitles{$mapid};
1.556     raeburn  2457:             $$symbp{$mapid}=$$mapp{$id}.'___(all)';  # Added in rev. 1.57, but seems not to be used.
                   2458:                                                      # Lines 1038 and 1114 which use $symbp{$mapid}
                   2459:                                                      # are commented out in rev. 1.57
1.473     amueller 2460:         } else {
1.480     amueller 2461:             $$mapp{$id} = $$mapp{$mapid};
1.473     amueller 2462:         }
1.480     amueller 2463:         $$symbp{$id}=&Apache::lonnet::encode_symb($$mapp{$id},$resid,$srcf);
1.63      bowersj2 2464:     }
                   2465: }
                   2466: 
1.582     raeburn  2467: sub get_recursive {
                   2468:     my ($recurseup,$resdata,$what,$prefix) = @_; 
                   2469:     if ((ref($resdata) eq 'HASH') && (ref($recurseup) eq 'ARRAY')) {
                   2470:         foreach my $item (@{$recurseup}) {
                   2471:             my $norecursechk=$prefix.'.'.$item.'___(all).'.$what;
                   2472:             if (defined($resdata->{$norecursechk})) {
                   2473:                 if ($what =~ /\.(encrypturl|hiddenresource)$/) {
                   2474:                     my $type = $resdata->{$norecursechk.'.type'};
                   2475:                     return [$resdata->{$norecursechk},$type,$item];
                   2476:                 } else {
                   2477:                     last;
                   2478:                 }
                   2479:             }
                   2480:             my $recursechk=$prefix.'.'.$item.'___(rec).'.$what;
                   2481:             if (defined($resdata->{$recursechk})) {
                   2482:                 my $type = $resdata->{$recursechk.'.type'};
                   2483:                 return [$resdata->{$recursechk},$type,$item];
                   2484:             }
                   2485:         }
                   2486:     }
                   2487:     return;
                   2488: }
                   2489: 
1.208     www      2490: 
1.562     damieng  2491: # Tells if a parameter type is a date.
                   2492: #
                   2493: # @param {string} type - parameter type
                   2494: # @returns{boolean} - true if it is a date
1.213     www      2495: sub isdateparm {
                   2496:     my $type=shift;
                   2497:     return (($type=~/^date/) && (!($type eq 'date_interval')));
                   2498: }
                   2499: 
1.589     raeburn  2500: # Determine if parameter type is specialized string type (i.e.,
                   2501: # not just string or string_yesno.  
                   2502: 
                   2503: sub is_specialstring {
                   2504:     my $type=shift;
1.603     raeburn  2505:     return (($type=~/^string_/) && ($type ne 'string_yesno'));
1.589     raeburn  2506: }
                   2507: 
1.562     damieng  2508: # Prints the HTML and Javascript to select parameters, with various shortcuts.
1.468     amueller 2509: #
1.581     raeburn  2510: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      2511: sub parmmenu {
1.581     raeburn  2512:     my ($r)=@_;
1.208     www      2513:     $r->print(<<ENDSCRIPT);
                   2514: <script type="text/javascript">
1.454     bisitz   2515: // <![CDATA[
1.208     www      2516:     function checkall(value, checkName) {
1.453     schualex 2517: 
                   2518:         var li = "_li";
                   2519:         var displayOverview = "";
                   2520:         
                   2521:         if (value == false) {
                   2522:             displayOverview = "none"
                   2523:         }
                   2524: 
1.562     damieng  2525:         for (i=0; i<document.forms.parmform.elements.length; i++) {
1.208     www      2526:             ele = document.forms.parmform.elements[i];
                   2527:             if (ele.name == checkName) {
                   2528:                 document.forms.parmform.elements[i].checked=value;
                   2529:             }
                   2530:         }
                   2531:     }
1.210     www      2532: 
                   2533:     function checkthis(thisvalue, checkName) {
1.562     damieng  2534:         for (i=0; i<document.forms.parmform.elements.length; i++) {
1.210     www      2535:             ele = document.forms.parmform.elements[i];
                   2536:             if (ele.name == checkName) {
1.562     damieng  2537:                 if (ele.value == thisvalue) {
                   2538:                     document.forms.parmform.elements[i].checked=true;
                   2539:                 }
1.210     www      2540:             }
                   2541:         }
                   2542:     }
                   2543: 
                   2544:     function checkdates() {
1.562     damieng  2545:         checkthis('duedate','pscat');
                   2546:         checkthis('opendate','pscat');
                   2547:         checkthis('answerdate','pscat');
1.218     www      2548:     }
                   2549: 
                   2550:     function checkdisset() {
1.562     damieng  2551:         checkthis('discussend','pscat');
                   2552:         checkthis('discusshide','pscat');
                   2553:         checkthis('discussvote','pscat');
1.218     www      2554:     }
                   2555: 
                   2556:     function checkcontdates() {
1.562     damieng  2557:         checkthis('contentopen','pscat');
                   2558:         checkthis('contentclose','pscat');
1.218     www      2559:     }
1.446     bisitz   2560: 
1.210     www      2561:     function checkvisi() {
1.562     damieng  2562:         checkthis('hiddenresource','pscat');
                   2563:         checkthis('encrypturl','pscat');
                   2564:         checkthis('problemstatus','pscat');
                   2565:         checkthis('contentopen','pscat');
                   2566:         checkthis('opendate','pscat');
1.210     www      2567:     }
                   2568: 
                   2569:     function checkparts() {
1.562     damieng  2570:         checkthis('hiddenparts','pscat');
                   2571:         checkthis('display','pscat');
                   2572:         checkthis('ordered','pscat');
1.210     www      2573:     }
                   2574: 
                   2575:     function checkstandard() {
                   2576:         checkall(false,'pscat');
1.562     damieng  2577:         checkdates();
                   2578:         checkthis('weight','pscat');
                   2579:         checkthis('maxtries','pscat');
                   2580:         checkthis('type','pscat');
                   2581:         checkthis('problemstatus','pscat');
1.210     www      2582:     }
                   2583: 
1.454     bisitz   2584: // ]]>
1.208     www      2585: </script>
                   2586: ENDSCRIPT
1.453     schualex 2587: 
1.491     bisitz   2588:     $r->print('<hr />');
1.581     raeburn  2589:     &shortCuts($r);
1.491     bisitz   2590:     $r->print('<hr />');
1.453     schualex 2591: }
1.562     damieng  2592: 
                   2593: # Returns parameter categories.
                   2594: #
                   2595: # @returns {hash} - category name -> title in English
1.465     amueller 2596: sub categories {
                   2597:     return ('time_settings' => 'Time Settings',
                   2598:     'grading' => 'Grading',
                   2599:     'tries' => 'Tries',
                   2600:     'problem_appearance' => 'Problem Appearance',
                   2601:     'behaviour_of_input_fields' => 'Behaviour of Input Fields',
                   2602:     'hiding' => 'Hiding',
                   2603:     'high_level_randomization' => 'High Level Randomization',
                   2604:     'slots' => 'Slots',
                   2605:     'file_submission' => 'File Submission',
                   2606:     'misc' => 'Miscellaneous' ); 
                   2607: }
                   2608: 
1.562     damieng  2609: # Returns the category for each parameter.
                   2610: #
                   2611: # @returns {hash} - parameter name -> category name
1.465     amueller 2612: sub lookUpTableParameter {
                   2613:  
                   2614:     return ( 
                   2615:         'opendate' => 'time_settings',
                   2616:         'duedate' => 'time_settings',
                   2617:         'answerdate' => 'time_settings',
1.622     raeburn  2618:         'grace' => 'time_settings',
1.465     amueller 2619:         'interval' => 'time_settings',
                   2620:         'contentopen' => 'time_settings',
                   2621:         'contentclose' => 'time_settings',
                   2622:         'discussend' => 'time_settings',
1.560     damieng  2623:         'printstartdate' => 'time_settings',
                   2624:         'printenddate' => 'time_settings',
1.465     amueller 2625:         'weight' => 'grading',
                   2626:         'handgrade' => 'grading',
                   2627:         'maxtries' => 'tries',
                   2628:         'hinttries' => 'tries',
1.503     raeburn  2629:         'randomizeontries' => 'tries',
1.465     amueller 2630:         'type' => 'problem_appearance',
                   2631:         'problemstatus' => 'problem_appearance',
                   2632:         'display' => 'problem_appearance',
                   2633:         'ordered' => 'problem_appearance',
                   2634:         'numbubbles' => 'problem_appearance',
                   2635:         'tol' => 'behaviour_of_input_fields',
                   2636:         'sig' => 'behaviour_of_input_fields',
                   2637:         'turnoffunit' => 'behaviour_of_input_fields',
                   2638:         'hiddenresource' => 'hiding',
                   2639:         'hiddenparts' => 'hiding',
                   2640:         'discusshide' => 'hiding',
                   2641:         'buttonshide' => 'hiding',
                   2642:         'turnoffeditor' => 'hiding',
                   2643:         'encrypturl' => 'hiding',
1.587     raeburn  2644:         'deeplink' => 'hiding',
1.465     amueller 2645:         'randomorder' => 'high_level_randomization',
                   2646:         'randompick' => 'high_level_randomization',
                   2647:         'available' => 'slots',
                   2648:         'useslots' => 'slots',
                   2649:         'availablestudent' => 'slots',
                   2650:         'uploadedfiletypes' => 'file_submission',
                   2651:         'maxfilesize' => 'file_submission',
                   2652:         'cssfile' => 'misc',
                   2653:         'mapalias' => 'misc',
                   2654:         'acc' => 'misc',
                   2655:         'maxcollaborators' => 'misc',
                   2656:         'scoreformat' => 'misc',
1.514     raeburn  2657:         'lenient' => 'grading',
1.519     raeburn  2658:         'retrypartial' => 'tries',
1.521     raeburn  2659:         'discussvote'  => 'misc',
1.621     raeburn  2660:         'texdisplay' => 'misc',
1.584     raeburn  2661:         'examcode' => 'high_level_randomization',
1.575     raeburn  2662:     );
1.465     amueller 2663: }
                   2664: 
1.562     damieng  2665: # Adds the given parameter name to an array of arrays listing all parameters for each category.
                   2666: #
                   2667: # @param {string} $name - parameter name
                   2668: # @param {array reference} $catList - array reference category name -> array reference of parameter names
1.465     amueller 2669: sub whatIsMyCategory {
                   2670:     my $name = shift;
                   2671:     my $catList = shift;
                   2672:     my @list;
                   2673:     my %lookUpList = &lookUpTableParameter; #Initilize the lookupList
                   2674:     my $cat = $lookUpList{$name};
                   2675:     if (defined($cat)) {
                   2676:         if (!defined($$catList{$cat})){
                   2677:             push @list, ($name);
                   2678:             $$catList{$cat} = \@list;
                   2679:         } else {
                   2680:             push @{${$catList}{$cat}}, ($name);     
                   2681:         }
                   2682:     } else {
                   2683:         if (!defined($$catList{'misc'})){
                   2684:             push @list, ($name);
                   2685:             $$catList{'misc'} = \@list;
                   2686:         } else {
                   2687:             push @{${$catList}{'misc'}}, ($name);     
                   2688:         }
                   2689:     }        
                   2690: }
                   2691: 
1.562     damieng  2692: # Sorts parameter names based on appearance order.
                   2693: #
                   2694: # @param {array reference} name - array reference of parameter names
                   2695: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   2696: # @returns {Array} - array of parameter names
1.465     amueller 2697: sub keysindisplayorderCategory {
                   2698:     my ($name,$keyorder)=@_;
                   2699:     return sort {
1.473     amueller 2700:         $$keyorder{'parameter_0_'.$a} <=> $$keyorder{'parameter_0_'.$b}; 
1.465     amueller 2701:     } ( @{$name});
                   2702: }
                   2703: 
1.562     damieng  2704: # Returns a hash category name -> order, starting at 1 (integer)
                   2705: #
                   2706: # @returns {hash}
1.467     amueller 2707: sub category_order {
                   2708:     return (
                   2709:         'time_settings' => 1,
                   2710:         'grading' => 2,
                   2711:         'tries' => 3,
                   2712:         'problem_appearance' => 4,
                   2713:         'hiding' => 5,
                   2714:         'behaviour_of_input_fields' => 6,
                   2715:         'high_level_randomization'  => 7,
                   2716:         'slots' => 8,
                   2717:         'file_submission' => 9,
                   2718:         'misc' => 10
                   2719:     );
                   2720: 
                   2721: }
1.453     schualex 2722: 
1.562     damieng  2723: # Prints HTML to let the user select parameters, from a list of all parameters organized by category.
                   2724: #
                   2725: # @param {Apache2::RequestRec} $r - the Apache request
                   2726: # @param {hash reference} $allparms - hash parameter name -> parameter title
                   2727: # @param {array reference} $pscat - list of selected parameter names
                   2728: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
1.453     schualex 2729: sub parmboxes {
                   2730:     my ($r,$allparms,$pscat,$keyorder)=@_;
1.548     raeburn  2731:     my %categories = &categories();
1.467     amueller 2732:     my %category_order = &category_order();
1.465     amueller 2733:     my %categoryList = (
                   2734:         'time_settings' => [],
                   2735:         'grading' => [],
                   2736:         'tries' => [],
                   2737:         'problem_appearance' => [],
                   2738:         'behaviour_of_input_fields' => [],
                   2739:         'hiding' => [],
                   2740:         'high_level_randomization' => [],
                   2741:         'slots' => [],
                   2742:         'file_submission' => [],
                   2743:         'misc' => [],
1.489     bisitz   2744:     );
1.510     www      2745: 
1.548     raeburn  2746:     foreach my $tempparameter (keys(%$allparms)) {
1.465     amueller 2747:         &whatIsMyCategory($tempparameter, \%categoryList);
                   2748:     }
1.453     schualex 2749:     #part to print the parm-list
1.618     raeburn  2750:     $Text::Wrap::columns=60;
                   2751:     $Text::Wrap::separator='<br />';
1.536     raeburn  2752:     foreach my $key (sort { $category_order{$a} <=> $category_order{$b} } keys(%categoryList)) {
                   2753:         next if (@{$categoryList{$key}} == 0);
                   2754:         next if ($key eq '');
                   2755:         $r->print('<div class="LC_Box LC_400Box">'
                   2756:                  .'<h4 class="LC_hcell">'.&mt($categories{$key}).'</h4>'."\n");
                   2757:         foreach my $tempkey (&keysindisplayorderCategory($categoryList{$key},$keyorder)) {
1.575     raeburn  2758:             next if ($tempkey eq '');
1.536     raeburn  2759:             $r->print('<span class="LC_nobreak">'
                   2760:                      .'<label><input type="checkbox" name="pscat" '
                   2761:                      .'value="'.$tempkey.'" ');
                   2762:             if ($$pscat[0] eq "all" || grep $_ eq $tempkey, @{$pscat}) {
                   2763:                 $r->print( ' checked="checked"');
                   2764:             }
1.617     raeburn  2765:             $r->print(' />'.($$allparms{$tempkey}=~/\S/ ? 
                   2766:                              Text::Wrap::wrap('','&nbsp;'x4,$$allparms{$tempkey})
                   2767:                              : $tempkey)
1.536     raeburn  2768:                      .'</label></span><br />'."\n");
1.465     amueller 2769:         }
1.536     raeburn  2770:         $r->print('</div>');
1.465     amueller 2771:     }
1.536     raeburn  2772:     $r->print("\n");
1.453     schualex 2773: }
1.562     damieng  2774: 
                   2775: # Prints HTML with shortcuts to select groups of parameters in one click, or deselect all.
1.468     amueller 2776: #
1.562     damieng  2777: # @param {Apache2::RequestRec} $r - the Apache request
1.453     schualex 2778: sub shortCuts {
1.581     raeburn  2779:     my ($r)=@_;
1.453     schualex 2780: 
1.491     bisitz   2781:     # Parameter Selection
                   2782:     $r->print(
                   2783:         &Apache::lonhtmlcommon::start_funclist(&mt('Parameter Selection'))
                   2784:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2785:             '<a href="javascript:checkall(true, \'pscat\')">'.&mt('Select All').'</a>')
                   2786:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2787:             '<a href="javascript:checkstandard()">'.&mt('Select Common Only').'</a>')
                   2788:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2789:             '<a href="javascript:checkall(false, \'pscat\')">'.&mt('Unselect All').'</a>')
                   2790:        .&Apache::lonhtmlcommon::end_funclist()
                   2791:     );
                   2792: 
                   2793:     # Add Selection for...
                   2794:     $r->print(
                   2795:         &Apache::lonhtmlcommon::start_funclist(&mt('Add Selection for...'))
                   2796:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2797:             '<a href="javascript:checkdates()">'.&mt('Problem Dates').'</a>')
                   2798:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2799:             '<a href="javascript:checkcontdates()">'.&mt('Content Dates').'</a>')
                   2800:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2801:             '<a href="javascript:checkdisset()">'.&mt('Discussion Settings').'</a>')
                   2802:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2803:             '<a href="javascript:checkvisi()">'.&mt('Visibilities').'</a>')
                   2804:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2805:             '<a href="javascript:checkparts()">'.&mt('Part Parameters').'</a>')
                   2806:        .&Apache::lonhtmlcommon::end_funclist()
                   2807:     );
1.208     www      2808: }
                   2809: 
1.562     damieng  2810: # Prints HTML to select parts to view (except for the title).
                   2811: # Used by table and overview modes.
                   2812: #
                   2813: # @param {Apache2::RequestRec} $r - the Apache request
                   2814: # @param {hash reference} $allparts - hash parameter part -> part title
                   2815: # @param {array reference} $psprt - list of selected parameter parts
1.209     www      2816: sub partmenu {
1.446     bisitz   2817:     my ($r,$allparts,$psprt)=@_;
1.523     raeburn  2818:     my $selsize = 1+scalar(keys(%{$allparts}));
                   2819:     if ($selsize > 8) {
                   2820:         $selsize = 8;
                   2821:     }
1.446     bisitz   2822: 
1.523     raeburn  2823:     $r->print('<select multiple="multiple" name="psprt" size="'.$selsize.'">');
1.208     www      2824:     $r->print('<option value="all"');
1.562     damieng  2825:     $r->print(' selected="selected"') unless (@{$psprt}); # useless, the array is never empty
1.208     www      2826:     $r->print('>'.&mt('All Parts').'</option>');
                   2827:     my %temphash=();
                   2828:     foreach (@{$psprt}) { $temphash{$_}=1; }
1.234     albertel 2829:     foreach my $tempkey (sort {
1.560     damieng  2830:                 if ($a==$b) { return ($a cmp $b) } else { return ($a <=> $b); }
                   2831:             } keys(%{$allparts})) {
                   2832:         unless ($tempkey =~ /\./) {
                   2833:             $r->print('<option value="'.$tempkey.'"');
                   2834:             if ($$psprt[0] eq "all" ||  $temphash{$tempkey}) {
                   2835:                 $r->print(' selected="selected"');
                   2836:             }
                   2837:             $r->print('>'.$$allparts{$tempkey}.'</option>');
1.473     amueller 2838:         }
1.208     www      2839:     }
1.446     bisitz   2840:     $r->print('</select>');
1.209     www      2841: }
                   2842: 
1.562     damieng  2843: # Prints HTML to select a user and/or a group.
                   2844: # Used by table mode.
                   2845: #
                   2846: # @param {Apache2::RequestRec} $r - the Apache request
                   2847: # @param {string} $uname - selected user name
                   2848: # @param {string} $id - selected Student/Employee ID
                   2849: # @param {string} $udom - selected user domain
                   2850: # @param {string} $csec - selected section name
                   2851: # @param {string} $cgroup - selected group name
                   2852: # @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general')
                   2853: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   2854: # @param {string} $pssymb - resource symb (when a single resource is selected)
1.209     www      2855: sub usermenu {
1.553     raeburn  2856:     my ($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,$usersgroups,$pssymb)=@_;
1.209     www      2857:     my $chooseopt=&Apache::loncommon::select_dom_form($udom,'udom').' '.
1.596     raeburn  2858:                   &Apache::loncommon::selectstudent_link('parmform','uname','udom','condition').
                   2859:                   &Apache::lonhtmlcommon::scripttag(<<ENDJS);
                   2860: function setCourseadv(form,caller) {
                   2861:     if (caller.value == 'st') {
                   2862:         form.courseadv.value = 'none';
                   2863:     } else {
                   2864:         form.courseadv.value = '';
                   2865:     }
                   2866:     return;
                   2867: }
                   2868: ENDJS
1.412     bisitz   2869: 
1.596     raeburn  2870:     my (%chkroles,$stuonly,$courseadv);
                   2871:     if ($env{'form.userroles'} eq 'any') {
                   2872:         $chkroles{'any'} = ' checked="checked"';
                   2873:     } else {
                   2874:         $chkroles{'st'} = ' checked="checked"';
                   2875:         $courseadv = 'none';
                   2876:     }
                   2877:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   2878:     if ($crstype eq 'Community') {
                   2879:         $stuonly = &mt('member only');
                   2880:     } else {
                   2881:         $stuonly = &mt('student only');
                   2882:     }
                   2883:     $chooseopt .= '<br /><span class="LC_cusr_subheading">'.
                   2884:                   &mt("User's role").':&nbsp;'.
                   2885:                   '<label><input type="radio" name="userroles" value="st"'.$chkroles{'st'}.' onclick="setCourseadv(this.form,this);" />'.
                   2886:                   $stuonly.'</label>&nbsp;&nbsp;'.
                   2887:                   '<label><input type="radio" name="userroles" value="any"'.$chkroles{'any'}.' onclick="setCourseadv(this.form,this);" />'.
                   2888:                   &mt('any role').'</label><input type="hidden" id="courseadv" name="courseadv" value="'.$courseadv.'" /></span>';
1.209     www      2889:     my $sections='';
1.300     albertel 2890:     my %sectionhash = &Apache::loncommon::get_sections();
                   2891: 
1.269     raeburn  2892:     my $groups;
1.553     raeburn  2893:     my %grouphash;
                   2894:     if (($pssymb) || &Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   2895:         %grouphash = &Apache::longroup::coursegroups();
                   2896:     } elsif ($env{'request.course.groups'} ne '') {
1.585     raeburn  2897:         map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'});
1.553     raeburn  2898:     }
1.299     albertel 2899: 
1.412     bisitz   2900:     my $g_s_header='';
                   2901:     my $g_s_footer='';
1.446     bisitz   2902: 
1.552     raeburn  2903:     my $currsec = $env{'request.course.sec'};
                   2904:     if ($currsec) {
                   2905:         $sections=&mt('Section:').' '.$currsec;
                   2906:         if (%grouphash) {
                   2907:             $sections .= ';'.('&nbsp;' x2);
                   2908:         }
                   2909:     } elsif (%sectionhash && $currsec eq '') {
1.412     bisitz   2910:         $sections=&mt('Section:').' <select name="csec"';
1.299     albertel 2911:         if (%grouphash && $parmlev ne 'full') {
1.269     raeburn  2912:             $sections .= qq| onchange="group_or_section('csec')" |;
                   2913:         }
                   2914:         $sections .= '>';
1.548     raeburn  2915:     foreach my $section ('',sort(keys(%sectionhash))) {
1.473     amueller 2916:         $sections.='<option value="'.$section.'" '.
                   2917:         ($section eq $csec?'selected="selected"':'').'>'.$section.
1.275     raeburn  2918:                                                               '</option>';
1.209     www      2919:         }
                   2920:         $sections.='</select>';
1.269     raeburn  2921:     }
1.412     bisitz   2922: 
1.552     raeburn  2923:     if (%sectionhash && %grouphash && $parmlev ne 'full' && $currsec eq '') {
1.412     bisitz   2924:         $sections .= '&nbsp;'.&mt('or').'&nbsp;';
1.269     raeburn  2925:         $sections .= qq|
                   2926: <script type="text/javascript">
1.454     bisitz   2927: // <![CDATA[
1.269     raeburn  2928: function group_or_section(caller) {
                   2929:    if (caller == "cgroup") {
                   2930:        if (document.parmform.cgroup.selectedIndex != 0) {
                   2931:            document.parmform.csec.selectedIndex = 0;
                   2932:        }
                   2933:    } else {
                   2934:        if (document.parmform.csec.selectedIndex != 0) {
                   2935:            document.parmform.cgroup.selectedIndex = 0;
                   2936:        }
                   2937:    }
                   2938: }
1.454     bisitz   2939: // ]]>
1.269     raeburn  2940: </script>
                   2941: |;
1.554     raeburn  2942:     } else {
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:     return;
                   2948: }
1.454     bisitz   2949: // ]]>
1.269     raeburn  2950: </script>
                   2951: |;
1.446     bisitz   2952:     }
1.299     albertel 2953: 
                   2954:     if (%grouphash) {
1.597     raeburn  2955:         $groups=&mt('Group').': <select name="cgroup"';
1.552     raeburn  2956:         if (%sectionhash && $env{'form.action'} eq 'settable' && $currsec eq '') {
1.269     raeburn  2957:             $groups .= qq| onchange="group_or_section('cgroup')" |;
                   2958:         }
                   2959:         $groups .= '>';
1.548     raeburn  2960:         foreach my $grp ('',sort(keys(%grouphash))) {
1.275     raeburn  2961:             $groups.='<option value="'.$grp.'" ';
                   2962:             if ($grp eq $cgroup) {
                   2963:                 unless ((defined($uname)) && ($grp eq '')) {
                   2964:                     $groups .=  'selected="selected" ';
                   2965:                 }
                   2966:             } elsif (!defined($cgroup)) {
                   2967:                 if (@{$usersgroups} == 1) {
                   2968:                     if ($grp eq $$usersgroups[0]) {
                   2969:                         $groups .=  'selected="selected" ';
                   2970:                     }
                   2971:                 }
                   2972:             }
                   2973:             $groups .= '>'.$grp.'</option>';
1.269     raeburn  2974:         }
                   2975:         $groups.='</select>';
                   2976:     }
1.412     bisitz   2977: 
1.445     neumanie 2978:     if (%sectionhash || %grouphash) {
1.446     bisitz   2979:         $r->print(&Apache::lonhtmlcommon::row_title(&mt('Group/Section')));
                   2980:         $r->print($sections.$groups);
1.448     bisitz   2981:         $r->print(&Apache::lonhtmlcommon::row_closure());
1.554     raeburn  2982:     } else {
                   2983:         $r->print($sections); 
1.445     neumanie 2984:     }
1.446     bisitz   2985: 
                   2986:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('User')));
1.443     neumanie 2987:     $r->print(&mt('For User [_1] or Student/Employee ID [_2] at Domain [_3]'
1.412     bisitz   2988:                  ,'<input type="text" value="'.$uname.'" size="12" name="uname" />'
                   2989:                  ,'<input type="text" value="'.$id.'" size="12" name="id" /> '
1.446     bisitz   2990:                  ,$chooseopt));
1.209     www      2991: }
                   2992: 
1.562     damieng  2993: # Prints HTML to select parameters from a list of all parameters.
                   2994: # Uses parmmenu and parmboxes.
                   2995: # Used by table and overview modes.
1.468     amueller 2996: #
1.562     damieng  2997: # @param {Apache2::RequestRec} $r - the Apache request
                   2998: # @param {hash reference} $allparms - hash parameter name -> parameter title
                   2999: # @param {array reference} $pscat - list of selected parameter names
                   3000: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3001: # @param {string} [$divid] - name used to give an id to the HTML element for the scroll box
1.209     www      3002: sub displaymenu {
1.581     raeburn  3003:     my ($r,$allparms,$pscat,$keyorder,$divid)=@_;
1.510     www      3004: 
1.445     neumanie 3005:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.510     www      3006:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parameters to View')));
                   3007: 
1.581     raeburn  3008:     &parmmenu($r);
1.536     raeburn  3009:     $r->print(&Apache::loncommon::start_scrollbox('480px','440px','200px',$divid));
1.510     www      3010:     &parmboxes($r,$allparms,$pscat,$keyorder);
                   3011:     $r->print(&Apache::loncommon::end_scrollbox());
                   3012: 
                   3013:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.453     schualex 3014:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.510     www      3015:  
1.209     www      3016: }
                   3017: 
1.562     damieng  3018: # Prints HTML to select a map.
                   3019: # Used by table mode and overview mode.
                   3020: #
                   3021: # @param {Apache2::RequestRec} $r - the Apache request
1.566     damieng  3022: # @param {hash reference} $allmaps - hash map pc -> map src
                   3023: # @param {string} $pschp - selected map pc, or 'all'
1.562     damieng  3024: # @param {hash reference} $maptitles - hash map id or src -> map title
1.566     damieng  3025: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' or resource symb
1.610     raeburn  3026: # @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general')
1.445     neumanie 3027: sub mapmenu {
1.610     raeburn  3028:     my ($r,$allmaps,$pschp,$maptitles,$symbp,$parmlev)=@_;
1.468     amueller 3029:     my %allmaps_inverted = reverse %$allmaps;
1.461     neumanie 3030:     my $navmap = Apache::lonnavmaps::navmap->new();
                   3031:     my $tree=[];
                   3032:     my $treeinfo={};
                   3033:     if (defined($navmap)) {
1.499     raeburn  3034:         my $it=$navmap->getIterator(undef,undef,undef,1,1,undef);
1.461     neumanie 3035:         my $curRes;
                   3036:         my $depth = 0;
1.468     amueller 3037:         my %parent = ();
                   3038:         my $startcount = 5;
                   3039:         my $lastcontainer = $startcount;
                   3040: # preparing what is to show ...
1.461     neumanie 3041:         while ($curRes = $it->next()) {
                   3042:             if ($curRes == $it->BEGIN_MAP()) {
                   3043:                 $depth++;
1.468     amueller 3044:                 $parent{$depth}= $lastcontainer;
1.461     neumanie 3045:             }
                   3046:             if ($curRes == $it->END_MAP()) {
                   3047:                 $depth--;
1.468     amueller 3048:                 $lastcontainer = $parent{$depth};
1.461     neumanie 3049:             }
                   3050:             if (ref($curRes)) {
1.468     amueller 3051:                 my $symb = $curRes->symb();
                   3052:                 my $ressymb = $symb;
1.461     neumanie 3053:                 if (($curRes->is_sequence()) || ($curRes->is_page())) {
                   3054:                     my $type = 'sequence';
                   3055:                     if ($curRes->is_page()) {
                   3056:                         $type = 'page';
                   3057:                     }
                   3058:                     my $id= $curRes->id();
1.468     amueller 3059:                     my $srcf = $curRes->src();
                   3060:                     my $resource_name = &Apache::lonnet::gettitle($srcf);
                   3061:                     if(!exists($treeinfo->{$id})) {
                   3062:                         push(@$tree,$id);
1.473     amueller 3063:                         my $enclosing_map_folder = &Apache::lonnet::declutter($curRes->enclosing_map_src());        
1.468     amueller 3064:                         $treeinfo->{$id} = {
1.461     neumanie 3065:                                     depth => $depth,
                   3066:                                     type  => $type,
1.468     amueller 3067:                                     name  => $resource_name,
                   3068:                                     enclosing_map_folder => $enclosing_map_folder,
1.461     neumanie 3069:                                     };
1.462     neumanie 3070:                     }
1.461     neumanie 3071:                 }
                   3072:             }
                   3073:         }
1.462     neumanie 3074:     }
1.473     amueller 3075: # Show it ...    
1.610     raeburn  3076:     my $rowattr = ' id="mapmenu"';
                   3077:     if ($parmlev eq 'general') {
                   3078:         $rowattr .= ' style="display:none"';
                   3079:     }
                   3080:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Enclosing Map or Folder'),'','',$rowattr));
1.461     neumanie 3081:     if ((ref($tree) eq 'ARRAY') && (ref($treeinfo) eq 'HASH')) {
                   3082:         my $icon = '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" />';
1.497     bisitz   3083:         my $whitespace =
                   3084:             '<img src="'
                   3085:            .&Apache::loncommon::lonhttpdurl('/adm/lonIcons/whitespace_21.gif')
                   3086:            .'" alt="" />';
                   3087: 
1.498     bisitz   3088:         # Info about selectable folders/maps
                   3089:         $r->print(
                   3090:             '<div class="LC_info">'
1.508     www      3091:            .&mt('You can only select maps and folders which have modifiable settings.')
                   3092:            .' '.&Apache::loncommon::help_open_topic('Parameter_Set_Folder') 
1.498     bisitz   3093:            .'</div>'
                   3094:         );
                   3095: 
1.536     raeburn  3096:         $r->print(&Apache::loncommon::start_scrollbox('700px','680px','400px','mapmenuscroll'));
1.523     raeburn  3097:         $r->print(&Apache::loncommon::start_data_table(undef,'mapmenuinner'));
1.497     bisitz   3098: 
1.498     bisitz   3099:         # Display row: "All Maps or Folders"
                   3100:         $r->print(
1.523     raeburn  3101:             &Apache::loncommon::start_data_table_row(undef,'picklevel')
1.498     bisitz   3102:            .'<td>'
                   3103:            .'<label>'
                   3104:            .'<input type="radio" name="pschp"'
1.497     bisitz   3105:         );
                   3106:         $r->print(' checked="checked"') if ($pschp eq 'all' || !$pschp);
1.498     bisitz   3107:         $r->print(
                   3108:             ' value="all" />&nbsp;'.$icon.'&nbsp;'
                   3109:            .&mt('All Maps or Folders')
                   3110:            .'</label>'
                   3111:            .'<hr /></td>'
                   3112:            .&Apache::loncommon::end_data_table_row()
1.463     bisitz   3113:         );
1.497     bisitz   3114: 
1.532     raeburn  3115:         # Display row: "Main Content"
1.468     amueller 3116:         if (exists($$allmaps{1})) {
1.498     bisitz   3117:             $r->print(
                   3118:                 &Apache::loncommon::start_data_table_row()
                   3119:                .'<td>'
                   3120:                .'<label>'
                   3121:                .'<input type="radio" name="pschp" value="1"'
1.468     amueller 3122:             );
1.497     bisitz   3123:             $r->print(' checked="checked"') if ($pschp eq '1');
1.498     bisitz   3124:             $r->print(
                   3125:                 '/>&nbsp;'.$icon.'&nbsp;'
                   3126:                .$$maptitles{1}
                   3127:                .($$allmaps{1} !~/^uploaded/?' ['.$$allmaps{1}.']':'')
                   3128:                .'</label>'
                   3129:                .'</td>'
                   3130:                .&Apache::loncommon::end_data_table_row()
1.468     amueller 3131:             );
                   3132:         }
1.497     bisitz   3133: 
                   3134:         # Display rows for all course maps and folders
1.468     amueller 3135:         foreach my $id (@{$tree}) {
                   3136:             my ($mapid,$resid)=split(/\./,$id);
1.464     bisitz   3137:             # Indentation
1.468     amueller 3138:             my $depth = $treeinfo->{$id}->{'depth'};
1.464     bisitz   3139:             my $indent;
                   3140:             for (my $i = 0; $i < $depth; $i++) {
                   3141:                 $indent.= $whitespace;
                   3142:             }
1.461     neumanie 3143:             $icon =  '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" />';
1.468     amueller 3144:             if ($treeinfo->{$id}->{'type'} eq 'page') {
1.461     neumanie 3145:                 $icon = '<img src="/adm/lonIcons/navmap.page.open.gif" alt="" />';
                   3146:             }
1.468     amueller 3147:             my $symb_name = $$symbp{$id};
                   3148:             my ($front, $tail) = split (/___${resid}___/, $symb_name);
                   3149:             $symb_name = $tail;
1.498     bisitz   3150:             $r->print(
                   3151:                 &Apache::loncommon::start_data_table_row()
                   3152:                .'<td>'
                   3153:                .'<label>'
1.463     bisitz   3154:             );
1.498     bisitz   3155:             # Only offer radio button for folders/maps which can be parameterized
                   3156:             if ($allmaps_inverted{$symb_name}) {
                   3157:                 $r->print(
                   3158:                     '<input type ="radio" name="pschp"'
                   3159:                    .' value="'.$allmaps_inverted{$symb_name}.'"'
                   3160:                 );
                   3161:                 $r->print(' checked="checked"') if ($allmaps_inverted{$symb_name} eq $pschp);
                   3162:                 $r->print('/>');
                   3163:             } else {
                   3164:                 $r->print($whitespace);
1.461     neumanie 3165:             }
1.498     bisitz   3166:             $r->print(
                   3167:                 $indent.$icon.'&nbsp;'
                   3168:                .$treeinfo->{$id}->{name}
                   3169:                .($$allmaps{$mapid}!~/^uploaded/?' ['.$$allmaps{$mapid}.']':'')
                   3170:                .'</label>'
                   3171:                .'</td>'
                   3172:                .&Apache::loncommon::end_data_table_row()
1.463     bisitz   3173:             );
1.461     neumanie 3174:         }
1.497     bisitz   3175: 
1.523     raeburn  3176:         $r->print(&Apache::loncommon::end_data_table().
                   3177:                   '<br style="line-height:2px;" />'.
                   3178:                   &Apache::loncommon::end_scrollbox());
1.209     www      3179:     }
                   3180: }
                   3181: 
1.563     damieng  3182: # Prints HTML to select the parameter level (resource, map/folder or course).
                   3183: # Used by table and overview modes.
                   3184: #
                   3185: # @param {Apache2::RequestRec} $r - the Apache request
                   3186: # @param {hash reference} $alllevs - all parameter levels, hash English title -> value
                   3187: # @param {string} $parmlev - selected level value (full|map|general), or ''
1.209     www      3188: sub levelmenu {
1.446     bisitz   3189:     my ($r,$alllevs,$parmlev)=@_;
                   3190: 
1.548     raeburn  3191:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parameter Level').
                   3192:                                                 &Apache::loncommon::help_open_topic('Course_Parameter_Levels')));
1.474     amueller 3193:     $r->print('<select id="parmlev" name="parmlev" onchange="showHide_courseContent()">');
1.548     raeburn  3194:     foreach my $lev (reverse(sort(keys(%{$alllevs})))) {
                   3195:         $r->print('<option value="'.$$alllevs{$lev}.'"');
                   3196:         if ($parmlev eq $$alllevs{$lev}) {
                   3197:             $r->print(' selected="selected"');
                   3198:         }
                   3199:         $r->print('>'.&mt($lev).'</option>');
1.208     www      3200:     }
1.446     bisitz   3201:     $r->print("</select>");
1.208     www      3202: }
                   3203: 
1.211     www      3204: 
1.563     damieng  3205: # Returns HTML to select a section (with a select HTML element).
                   3206: # Used by overview mode.
                   3207: #
                   3208: # @param {array reference} $selectedsections - list of selected section ids
                   3209: # @returns {string}
1.211     www      3210: sub sectionmenu {
1.553     raeburn  3211:     my ($selectedsections)=@_;
1.300     albertel 3212:     my %sectionhash = &Apache::loncommon::get_sections();
1.553     raeburn  3213:     return '' if (!%sectionhash);
1.300     albertel 3214: 
1.552     raeburn  3215:     my (@possibles,$disabled);
                   3216:     if ($env{'request.course.sec'} ne '') {
                   3217:         @possibles = ($env{'request.course.sec'});
                   3218:         $selectedsections = [$env{'request.course.sec'}];
                   3219:         $disabled = ' disabled="disabled"';
                   3220:     } else {
                   3221:         @possibles = ('all',sort(keys(%sectionhash)));
                   3222:     }
1.553     raeburn  3223:     my $output = '<select name="Section" multiple="multiple" size="8"'.$disabled.'>';
1.552     raeburn  3224:     foreach my $s (@possibles) {
1.553     raeburn  3225:         $output .= '    <option value="'.$s.'"';
                   3226:         if ((@{$selectedsections}) && (grep(/^\Q$s\E$/,@{$selectedsections}))) {  
                   3227:             $output .= ' selected="selected"';
1.473     amueller 3228:         }
1.553     raeburn  3229:         $output .= '>'."$s</option>\n";
1.300     albertel 3230:     }
1.553     raeburn  3231:     $output .= "</select>\n";
                   3232:     return $output;
1.269     raeburn  3233: }
                   3234: 
1.563     damieng  3235: # Returns HTML to select a group (with a select HTML element).
                   3236: # Used by overview mode.
                   3237: #
                   3238: # @param {array reference} $selectedgroups - list of selected group names
                   3239: # @returns {string}
1.269     raeburn  3240: sub groupmenu {
1.553     raeburn  3241:     my ($selectedgroups)=@_;
                   3242:     my %grouphash;
                   3243:     if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   3244:         %grouphash = &Apache::longroup::coursegroups();
                   3245:     } elsif ($env{'request.course.groups'} ne '') {
1.585     raeburn  3246:          map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'});
1.553     raeburn  3247:     }
                   3248:     return '' if (!%grouphash);
1.299     albertel 3249: 
1.553     raeburn  3250:     my $output = '<select name="Group" multiple="multiple" size="8">';
1.299     albertel 3251:     foreach my $group (sort(keys(%grouphash))) {
1.553     raeburn  3252:         $output .= '    <option value="'.$group.'"';
                   3253:         if ((@{$selectedgroups}) && (grep(/^\Q$group\E$/,\@{$selectedgroups}))) {
                   3254:             $output .=  ' selected="selected"';
1.473     amueller 3255:         }
1.553     raeburn  3256:         $output .= '>'."$group</option>\n";
1.211     www      3257:     }
1.553     raeburn  3258:     $output .= "</select>\n";
                   3259:     return $output;
1.211     www      3260: }
                   3261: 
1.563     damieng  3262: # Returns an array with the given parameter split by comma.
                   3263: # Used by assessparms (table mode).
                   3264: #
                   3265: # @param {string} $keyp - the string to split
                   3266: # @returns {Array<string>}
1.210     www      3267: sub keysplit {
                   3268:     my $keyp=shift;
                   3269:     return (split(/\,/,$keyp));
                   3270: }
                   3271: 
1.563     damieng  3272: # Returns the keys in $name, sorted using $keyorder.
                   3273: # Parameters are sorted by key, which means they are sorted by part first, then by name.
                   3274: # Used by assessparms (table mode) for resource level.
                   3275: #
                   3276: # @param {hash reference} $name - parameter key -> parameter name
                   3277: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3278: # @returns {Array<string>}
1.210     www      3279: sub keysinorder {
                   3280:     my ($name,$keyorder)=@_;
                   3281:     return sort {
1.560     damieng  3282:         $$keyorder{$a} <=> $$keyorder{$b};
1.548     raeburn  3283:     } (keys(%{$name}));
1.210     www      3284: }
                   3285: 
1.563     damieng  3286: # Returns the keys in $name, sorted using $keyorder to sort parameters by name first, then by part.
                   3287: # Used by assessparms (table mode) for map and general levels.
                   3288: #
                   3289: # @param {hash reference} $name - parameter key -> parameter name
                   3290: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3291: # @returns {Array<string>}
1.236     albertel 3292: sub keysinorder_bytype {
                   3293:     my ($name,$keyorder)=@_;
                   3294:     return sort {
1.563     damieng  3295:         my $ta=(split('_',$a))[-1]; # parameter name
1.560     damieng  3296:         my $tb=(split('_',$b))[-1];
                   3297:         if ($$keyorder{'parameter_0_'.$ta} == $$keyorder{'parameter_0_'.$tb}) {
                   3298:             return ($a cmp $b);
                   3299:         }
                   3300:         $$keyorder{'parameter_0_'.$ta} <=> $$keyorder{'parameter_0_'.$tb};
1.548     raeburn  3301:     } (keys(%{$name}));
1.236     albertel 3302: }
                   3303: 
1.563     damieng  3304: # Returns the keys in $name, sorted using $keyorder to sort parameters by name.
                   3305: # Used by defaultsetter (parameter settings default actions).
                   3306: #
                   3307: # @param {hash reference} $name - hash parameter name -> parameter title
                   3308: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3309: # @returns {Array<string>}
1.211     www      3310: sub keysindisplayorder {
                   3311:     my ($name,$keyorder)=@_;
                   3312:     return sort {
1.560     damieng  3313:         $$keyorder{'parameter_0_'.$a} <=> $$keyorder{'parameter_0_'.$b};
1.548     raeburn  3314:     } (keys(%{$name}));
1.211     www      3315: }
                   3316: 
1.563     damieng  3317: # Prints HTML with a choice to sort results by realm or student first.
                   3318: # Used by overview mode.
                   3319: #
                   3320: # @param {Apache2::RequestRec} $r - the Apache request
                   3321: # @param {string} $sortorder - realmstudent|studentrealm
1.608     raeburn  3322: # @param {string} $context - newoverview|overview
1.214     www      3323: sub sortmenu {
1.608     raeburn  3324:     my ($r,$sortorder,$context)=@_;
                   3325:     my %text;
                   3326:     if ($context eq 'newoverview') {
                   3327:         %text = &Apache::lonlocal::texthash (
                   3328:                    realmstudent => 'Sort by location in course first, then student (group/section)',
                   3329:                    studentrealm => 'Sort by student (group/section) first, then location in course',
                   3330:         );
                   3331:     } else {
                   3332:         %text = &Apache::lonlocal::texthash (
                   3333:                    realmstudent => 'Sort by realm first, then student (group/section)',
                   3334:                    studentrealm => 'Sort by student (group/section) first, then realm',
                   3335:         );
1.214     www      3336:     }
1.608     raeburn  3337:     my %sortchecked = (
                   3338:        realmstudent => ' checked="checked"',
                   3339:        studentrealm => '',
                   3340:     );
1.214     www      3341:     if ($sortorder eq 'studentrealm') {
1.608     raeburn  3342:         $sortchecked{'studentrealm'} = $sortchecked{'realmstudent'};
                   3343:         $sortchecked{'realmstudent'} = '';
                   3344:     }
                   3345:     foreach my $sorttype ('realmstudent','studentrealm') {
                   3346:         $r->print('<br /><label><input type="radio" name="sortorder" value="'.$sorttype.'"'.$sortchecked{$sorttype}.' />'.
                   3347:                   $text{$sorttype}.'</label>');
1.214     www      3348:     }
                   3349: }
                   3350: 
1.563     damieng  3351: # Returns a hash parameter key -> order (integer) giving the order for some parameters.
                   3352: #
                   3353: # @returns {hash}
1.211     www      3354: sub standardkeyorder {
                   3355:     return ('parameter_0_opendate' => 1,
1.473     amueller 3356:         'parameter_0_duedate' => 2,
                   3357:         'parameter_0_answerdate' => 3,
1.622     raeburn  3358:         'parameter_0_grace' => 4,
                   3359:         'parameter_0_interval' => 5,
                   3360:         'parameter_0_weight' => 6,
                   3361:         'parameter_0_maxtries' => 7,
                   3362:         'parameter_0_hinttries' => 8,
                   3363:         'parameter_0_contentopen' => 9,
                   3364:         'parameter_0_contentclose' => 10,
                   3365:         'parameter_0_type' => 11,
                   3366:         'parameter_0_problemstatus' => 12,
                   3367:         'parameter_0_hiddenresource' => 13,
                   3368:         'parameter_0_hiddenparts' => 14,
                   3369:         'parameter_0_display' => 15,
                   3370:         'parameter_0_ordered' => 16,
                   3371:         'parameter_0_tol' => 17,
                   3372:         'parameter_0_sig' => 18,
                   3373:         'parameter_0_turnoffunit' => 19,
                   3374:         'parameter_0_discussend' => 20,
                   3375:         'parameter_0_discusshide' => 21,
                   3376:         'parameter_0_discussvote' => 22,
                   3377:         'parameter_0_printstartdate' => 23,
                   3378:         'parameter_0_printenddate' => 24);
1.211     www      3379: }
                   3380: 
1.59      matthew  3381: 
1.560     damieng  3382: # Table mode UI.
1.563     damieng  3383: # If nothing is selected, prints HTML forms to select resources, parts, parameters, user, group and section.
                   3384: # Otherwise, prints the parameter table, with a link to change the selection unless a single resource is selected.
                   3385: #
                   3386: # Parameters used from the request:
                   3387: # action - handler action (see handler), usermenu is checking for value 'settable'
                   3388: # cgroup - selected group
                   3389: # command - 'set': direct access to table mode for a resource
                   3390: # csec - selected section
                   3391: # dis - set when the "Update Display" button was used, used only to discard command 'set'
                   3392: # hideparmsel - can be 'hidden' to hide the parameter selection div initially and display the "Change Parameter Selection" link instead (which displays the div)
                   3393: # id - student/employee ID
                   3394: # parmlev - selected level (full|map|general)
                   3395: # part - selected part (unused ?)
                   3396: # pres_marker - &&&-separated parameter identifiers, "resource id&part_parameter name&level"
                   3397: # pres_type - &&&-separated parameter types
                   3398: # pres_value - &&&-separated parameter values
                   3399: # prevvisit - '1' if the user has submitted the form before
                   3400: # pscat (multiple values) - selected parameter names
1.566     damieng  3401: # pschp - selected map pc, or 'all'
1.563     damieng  3402: # psprt (multiple values) - list of selected parameter parts
                   3403: # filter - part of or whole parameter name, to be filtered out when parameters are displayed (unused ?)
                   3404: # recent_* (* = parameter type) - recent values entered by the user for parameter types
                   3405: # symb - resource symb (when a single resource is selected)
                   3406: # udom - selected user domain
                   3407: # uname - selected user name
                   3408: # url - used only with command 'set', the resource url
                   3409: #
                   3410: # @param {Apache2::RequestRec} $r - the Apache request
1.568     raeburn  3411: # @param $parm_permission - ref to hash of permissions
                   3412: #                           if $parm_permission->{'edit'} is true, editing is allowed.
1.30      www      3413: sub assessparms {
1.1       www      3414: 
1.568     raeburn  3415:     my ($r,$parm_permission) = @_;
1.201     www      3416: 
1.512     foxr     3417: 
                   3418: # -------------------------------------------------------- Variable declaration
1.566     damieng  3419:     my @ids=(); # resource and map ids
                   3420:     my %symbp=(); # hash map pc or resource/map id -> map src.'___(all)' or resource symb
                   3421:     my %mapp=(); # hash map pc or resource/map id -> enclosing map src
                   3422:     my %typep=(); # hash resource/map id -> resource type (file extension)
                   3423:     my %keyp=(); # hash resource/map id -> comma-separated list of parameter keys
                   3424:     my %uris=(); # hash resource/map id -> resource src
                   3425:     my %maptitles=(); # hash map pc or src -> map title
                   3426:     my %allmaps=(); # hash map pc -> map src
1.582     raeburn  3427:     my %allmaps_inverted=(); # hash map src -> map pc
1.563     damieng  3428:     my %alllevs=(); # hash English level title -> value
                   3429: 
                   3430:     my $uname; # selected user name
                   3431:     my $udom; # selected user domain
                   3432:     my $uhome; # server with the user's files, or 'no_host'
                   3433:     my $csec; # selected section name
                   3434:     my $cgroup; # selected group name
                   3435:     my @usersgroups = (); # list of the user groups
1.582     raeburn  3436:     my $numreclinks = 0;
1.446     bisitz   3437: 
1.190     albertel 3438:     my $coursename=$env{'course.'.$env{'request.course.id'}.'.description'};
1.187     www      3439: 
1.57      albertel 3440:     $alllevs{'Resource Level'}='full';
1.215     www      3441:     $alllevs{'Map/Folder Level'}='map';
1.57      albertel 3442:     $alllevs{'Course Level'}='general';
                   3443: 
1.563     damieng  3444:     my %allparms; # hash parameter name -> parameter title
                   3445:     my %allparts; # hash parameter part -> part title
1.512     foxr     3446: # ------------------------------------------------------------------------------
                   3447: 
1.210     www      3448: #
                   3449: # Order in which these parameters will be displayed
                   3450: #
1.211     www      3451:     my %keyorder=&standardkeyorder();
                   3452: 
1.512     foxr     3453: #    @ids=();
                   3454: #    %symbp=();       # These seem defined above already.
                   3455: #    %typep=();
1.43      albertel 3456: 
                   3457:     my $message='';
                   3458: 
1.190     albertel 3459:     $csec=$env{'form.csec'};
1.552     raeburn  3460:     if ($env{'request.course.sec'} ne '') {
                   3461:         $csec = $env{'request.course.sec'};    
                   3462:     }
                   3463: 
1.553     raeburn  3464: # Check group privs.
1.269     raeburn  3465:     $cgroup=$env{'form.cgroup'};
1.553     raeburn  3466:     my $noeditgrp; 
                   3467:     if ($cgroup ne '') {
                   3468:         unless (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   3469:             if (($env{'request.course.groups'} eq '') || 
1.585     raeburn  3470:                 (!grep(/^\Q$cgroup\E$/,split(/:/,$env{'request.course.groups'})))) {
1.553     raeburn  3471:                 $noeditgrp = 1;
                   3472:             }
                   3473:         }
                   3474:     }
1.188     www      3475: 
1.190     albertel 3476:     if      ($udom=$env{'form.udom'}) {
                   3477:     } elsif ($udom=$env{'request.role.domain'}) {
                   3478:     } elsif ($udom=$env{'user.domain'}) {
1.172     albertel 3479:     } else {
1.473     amueller 3480:         $udom=$r->dir_config('lonDefDomain');
1.172     albertel 3481:     }
1.468     amueller 3482:     
1.43      albertel 3483: 
1.134     albertel 3484:     my @pscat=&Apache::loncommon::get_env_multiple('form.pscat');
1.190     albertel 3485:     my $pschp=$env{'form.pschp'};
1.506     www      3486: 
                   3487: 
1.134     albertel 3488:     my @psprt=&Apache::loncommon::get_env_multiple('form.psprt');
1.516     www      3489:     if (!@psprt) { $psprt[0]='all'; }
1.506     www      3490:     if (($env{'form.part'}) && ($psprt[0] ne 'all')) { $psprt[0]=$env{'form.part'}; }
1.57      albertel 3491: 
1.43      albertel 3492:     my $pssymb='';
1.57      albertel 3493:     my $parmlev='';
1.446     bisitz   3494: 
1.190     albertel 3495:     unless ($env{'form.parmlev'}) {
1.57      albertel 3496:         $parmlev = 'map';
                   3497:     } else {
1.190     albertel 3498:         $parmlev = $env{'form.parmlev'};
1.57      albertel 3499:     }
1.26      www      3500: 
1.29      www      3501: # ----------------------------------------------- Was this started from grades?
                   3502: 
1.560     damieng  3503:     if (($env{'form.command'} eq 'set') && ($env{'form.url'}) &&
                   3504:             (!$env{'form.dis'})) {
1.473     amueller 3505:         my $url=$env{'form.url'};
                   3506:         $url=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
                   3507:         $pssymb=&Apache::lonnet::symbread($url);
                   3508:         if (!@pscat) { @pscat=('all'); }
                   3509:         $pschp='';
1.57      albertel 3510:         $parmlev = 'full';
1.190     albertel 3511:     } elsif ($env{'form.symb'}) {
1.473     amueller 3512:         $pssymb=$env{'form.symb'};
                   3513:         if (!@pscat) { @pscat=('all'); }
                   3514:         $pschp='';
1.57      albertel 3515:         $parmlev = 'full';
1.43      albertel 3516:     } else {
1.473     amueller 3517:         $env{'form.url'}='';
1.43      albertel 3518:     }
                   3519: 
1.190     albertel 3520:     my $id=$env{'form.id'};
1.43      albertel 3521:     if (($id) && ($udom)) {
1.555     raeburn  3522:         $uname=(&Apache::lonnet::idget($udom,[$id],'ids'))[1];
1.473     amueller 3523:         if ($uname) {
                   3524:             $id='';
                   3525:         } else {
                   3526:             $message=
1.540     bisitz   3527:                 '<p class="LC_warning">'.
                   3528:                 &mt('Unknown ID [_1] at domain [_2]',
                   3529:                     "'".$id."'","'".$udom."'").
                   3530:                 '</p>';
1.473     amueller 3531:         }
1.43      albertel 3532:     } else {
1.473     amueller 3533:         $uname=$env{'form.uname'};
1.43      albertel 3534:     }
                   3535:     unless ($udom) { $uname=''; }
                   3536:     $uhome='';
                   3537:     if ($uname) {
1.473     amueller 3538:         $uhome=&Apache::lonnet::homeserver($uname,$udom);
1.43      albertel 3539:         if ($uhome eq 'no_host') {
1.473     amueller 3540:             $message=
1.540     bisitz   3541:                 '<p class="LC_warning">'.
                   3542:                 &mt('Unknown user [_1] at domain [_2]',
                   3543:                     "'".$uname."'","'".$udom."'").
                   3544:                 '</p>';
1.473     amueller 3545:             $uname='';
1.12      www      3546:         } else {
1.473     amueller 3547:             $csec=&Apache::lonnet::getsection($udom,$uname,
                   3548:                           $env{'request.course.id'});
                   3549:             if ($csec eq '-1') {
1.596     raeburn  3550:                 my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   3551:                 if ($env{'form.userroles'} eq 'any') {
                   3552:                     if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) {
                   3553:                         $csec = $env{'request.course.sec'};
                   3554:                         $message = '<span class="LC_info">';
                   3555:                         if ($crstype eq 'Community') {
                   3556:                             $message .= &mt('User [_1] at domain [_2] has a non-member role in this community',
                   3557:                                             $uname,$udom);
                   3558:                         } else {
                   3559:                             $message .= &mt('User [_1] at domain [_2] has a non-student role in this course',
                   3560:                                             $uname,$udom);
                   3561:                         }
                   3562:                         $message .= '</span>';
                   3563:                     } else {
                   3564:                         my @possroles = ('in','ep','ta','cr');
                   3565:                         if ($crstype eq 'Community') {
                   3566:                             unshift(@possroles,'co');
                   3567:                         } else {
                   3568:                             unshift(@possroles,'cc');
                   3569:                         }
                   3570:                         my %not_student_roles =
                   3571:                             &Apache::lonnet::get_my_roles($uname,$udom,'userroles',['active'],
                   3572:                                                           \@possroles,[$udom],1,1);
                   3573:                         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   3574:                         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   3575:                         my %sections_by_role;
                   3576:                         foreach my $role (keys(%not_student_roles)) {
                   3577:                             if ($role =~ /^\Q$cnum:$cdom:\E([^:]+):(|[^:]+)$/) {
                   3578:                                 my ($rolename,$sec) = ($1,$2);
                   3579:                                 if ($rolename =~ m{^cr/}) {
                   3580:                                     $rolename = 'cr';
                   3581:                                 }
                   3582:                                 push(@{$sections_by_role{$rolename}},$sec);
                   3583:                             }
                   3584:                         }
                   3585:                         my $numroles = scalar(keys(%sections_by_role));
                   3586:                         if ($numroles) {
                   3587:                             foreach my $role (@possroles) {
                   3588:                                 if (ref($sections_by_role{$role}) eq 'ARRAY') {
                   3589:                                     my @secs = sort { $a <=> $b } @{$sections_by_role{$role}};
                   3590:                                     $csec = $secs[0];
                   3591:                                     last;
                   3592:                                 }
                   3593:                             }
                   3594:                         }
                   3595:                         if ($csec eq '-1') {
                   3596:                             $message = '<span class="LC_warning">';
                   3597:                             if ($crstype eq 'Community') {
                   3598:                                 $message .= &mt('User [_1] at domain [_2] does not have a role in this community',
                   3599:                                                 $uname,$udom);
                   3600:                             } else {
                   3601:                                 $message .= &mt('User [_1] at domain [_2] does not have a role in this course',
                   3602:                                                 $uname,$udom);
                   3603:                             }
                   3604:                             $message .= '</span>';
                   3605:                             $uname='';
                   3606:                             if ($env{'request.course.sec'} ne '') {
                   3607:                                 $csec=$env{'request.course.sec'};
                   3608:                             } else {
                   3609:                                 $csec=$env{'form.csec'};
                   3610:                             }
                   3611:                             $cgroup=$env{'form.cgroup'};
                   3612:                         } else {
                   3613:                             $message = '<span class="LC_info">';
                   3614:                             if ($crstype eq 'Community') {
                   3615:                                 $message .= &mt('User [_1] at domain [_2] has a non-member role in this community',
                   3616:                                          $uname,$udom);
                   3617:                             } else {
                   3618:                                 $message .= &mt('User [_1] at domain [_2] has a non-student role in this course',
                   3619:                                                 $uname,$udom);
                   3620:                             }
                   3621:                             $message .= '</span>';
                   3622:                         }
                   3623:                     }
1.594     raeburn  3624:                 } else {
1.596     raeburn  3625:                     $message = '<span class="LC_warning">';
                   3626:                     if ($crstype eq 'Community') {
                   3627:                         $message .= &mt('User [_1] at domain [_2] does not have a member role in this community',
                   3628:                                          $uname,$udom);
                   3629:                     } else {
                   3630:                          $message .= &mt('User [_1] at domain [_2] does not have a student role in this course',
                   3631:                                          $uname,$udom);
                   3632:                     }
                   3633:                     $message .= '</span>';
                   3634:                     $uname='';
                   3635:                     if ($env{'request.course.sec'} ne '') {
                   3636:                         $csec=$env{'request.course.sec'};
                   3637:                     } else {
                   3638:                         $csec=$env{'form.csec'};
                   3639:                     }
                   3640:                     $cgroup=$env{'form.cgroup'};
1.594     raeburn  3641:                 }
                   3642:             } elsif ($env{'request.course.sec'} ne '') {
                   3643:                 if ($csec ne $env{'request.course.sec'}) {
1.596     raeburn  3644:                     $message='<span class="LC_warning">'.
1.594     raeburn  3645:                               &mt("User '[_1]' at domain '[_2]' not in section '[_3]'",
                   3646:                                   $uname,$udom,$env{'request.course.sec'}).
                   3647:                               '</span>';
                   3648:                     $uname='';
                   3649:                     $csec=$env{'request.course.sec'};
                   3650:                 }
1.269     raeburn  3651:                 $cgroup=$env{'form.cgroup'};
1.596     raeburn  3652:             }
                   3653:             if ($uname ne '') {
1.473     amueller 3654:                 my %name=&Apache::lonnet::userenvironment($udom,$uname,
                   3655:                   ('firstname','middlename','lastname','generation','id'));
1.596     raeburn  3656:                 $message .= "\n<p>\n".&mt('Full Name').': '
                   3657:                             .$name{'firstname'}.' '.$name{'middlename'}.' '
                   3658:                             .$name{'lastname'}.' '.$name{'generation'}
                   3659:                             ."<br />\n".&mt('Student/Employee ID').': '.$name{'id'}.'</p>';
                   3660:                 @usersgroups = &Apache::lonnet::get_users_groups(
                   3661:                                    $udom,$uname,$env{'request.course.id'});
                   3662:                 if (@usersgroups > 0) {
                   3663:                     unless (grep(/^\Q$cgroup\E$/,@usersgroups)) {
                   3664:                         $cgroup = $usersgroups[0];
                   3665:                     }
                   3666:                 } else {
                   3667:                     $cgroup = '';
1.297     raeburn  3668:                 }
1.269     raeburn  3669:             }
1.12      www      3670:         }
1.43      albertel 3671:     }
1.2       www      3672: 
1.43      albertel 3673:     unless ($csec) { $csec=''; }
1.269     raeburn  3674:     unless ($cgroup) { $cgroup=''; }
1.12      www      3675: 
1.14      www      3676: # --------------------------------------------------------- Get all assessments
1.446     bisitz   3677:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 3678:                 \%mapp, \%symbp,\%maptitles,\%uris,
1.603     raeburn  3679:                 \%keyorder,undef,$pssymb);
1.63      bowersj2 3680: 
1.582     raeburn  3681:     %allmaps_inverted = reverse(%allmaps);
                   3682: 
1.57      albertel 3683:     $mapp{'0.0'} = '';
                   3684:     $symbp{'0.0'} = '';
1.99      albertel 3685: 
1.14      www      3686: # ---------------------------------------------------------- Anything to store?
1.568     raeburn  3687:     if ($env{'form.pres_marker'} && $parm_permission->{'edit'}) {
1.205     www      3688:         my @markers=split(/\&\&\&/,$env{'form.pres_marker'});
                   3689:         my @values=split(/\&\&\&/,$env{'form.pres_value'});
                   3690:         my @types=split(/\&\&\&/,$env{'form.pres_type'});
1.500     raeburn  3691:         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   3692:         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.504     raeburn  3693:         my $chome = $env{'course.'.$env{'request.course.id'}.'.home'};
                   3694:         my ($got_chostname,$chostname,$cmajor,$cminor);
                   3695:         my $totalstored = 0;
1.605     raeburn  3696:         my $totalskippeduser = 0;
1.546     raeburn  3697:         my $now = time;
1.473     amueller 3698:         for (my $i=0;$i<=$#markers;$i++) {
1.557     raeburn  3699:             my ($needsrelease,$needsnewer,$name,$namematch);
1.556     raeburn  3700:             if (($env{'request.course.sec'} ne '') && ($markers[$i] =~ /\&(9|10|11|12)$/)) {
1.552     raeburn  3701:                 next if ($csec ne $env{'request.course.sec'});
                   3702:             }
1.556     raeburn  3703:             if ($markers[$i] =~ /\&(8|7|6|5)$/) {
1.553     raeburn  3704:                 next if ($noeditgrp);
1.605     raeburn  3705:             } elsif ($markers[$i] =~ /\&(4|3|2|1)$/) {
                   3706:                 if ($uname eq '') {
                   3707:                     $totalskippeduser ++;
                   3708:                     next;
                   3709:                 }
1.557     raeburn  3710:             }
                   3711:             if ($markers[$i] =~ /\&(17|11|7|3)$/) {
                   3712:                 $namematch = 'maplevelrecurse';
                   3713:             }
1.556     raeburn  3714:             if ($markers[$i] =~ /^[\d.]+\&0_availablestudent\&(1|2|3|4)$/) {
1.437     raeburn  3715:                 my (@ok_slots,@fail_slots,@del_slots);
                   3716:                 my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
                   3717:                 my ($level,@all) =
                   3718:                     &parmval_by_symb('0.availablestudent',$pssymb,'',$uname,$udom,
                   3719:                                      $csec,$cgroup,$courseopt);
                   3720:                 foreach my $slot_name (split(/:/,$values[$i])) {
                   3721:                     next if ($slot_name eq '');
                   3722:                     if (&update_slots($slot_name,$cdom,$cnum,$pssymb,$uname,$udom) eq 'ok') {
                   3723:                         push(@ok_slots,$slot_name);
                   3724: 
                   3725:                     } else {
                   3726:                         push(@fail_slots,$slot_name);
                   3727:                     }
                   3728:                 }
                   3729:                 if (@ok_slots) {
                   3730:                     $values[$i] = join(':',@ok_slots);
                   3731:                 } else {
                   3732:                     $values[$i] = '';
                   3733:                 }
                   3734:                 if ($all[$level] ne '') {
                   3735:                     my @existing = split(/:/,$all[$level]);
                   3736:                     foreach my $slot_name (@existing) {
                   3737:                         if (!grep(/^\Q$slot_name\E$/,split(/:/,$values[$i]))) {
                   3738:                             if (&delete_slots($slot_name,$cdom,$cnum,$uname,$udom,$pssymb) eq 'ok') {
                   3739:                                 push(@del_slots,$slot_name);
                   3740:                             }
                   3741:                         }
                   3742:                     }
                   3743:                 }
1.554     raeburn  3744:             } elsif ($markers[$i] =~ /_(type|lenient|retrypartial|discussvote|examcode|printstartdate|printenddate|acc|interval)\&\d+$/) {
1.514     raeburn  3745:                 $name = $1;
1.533     raeburn  3746:                 my $val = $values[$i];
1.549     raeburn  3747:                 my $valmatch = '';
1.533     raeburn  3748:                 if ($name eq 'examcode') {
1.544     raeburn  3749:                     if (&Apache::lonnet::validCODE($values[$i])) {
                   3750:                         $val = 'valid';
                   3751:                     }
1.546     raeburn  3752:                 } elsif ($name eq 'printstartdate') {
                   3753:                     if ($val =~ /^\d+$/) {
                   3754:                         if ($val > $now) {
                   3755:                             $val = 'future';
                   3756:                         }
                   3757:                     } 
                   3758:                 } elsif ($name eq 'printenddate') {
                   3759:                     if ($val =~ /^\d+$/) {
                   3760:                         if ($val < $now) {
                   3761:                             $val = 'past';
                   3762:                         }
                   3763:                     }
1.549     raeburn  3764:                 } elsif (($name eq 'lenient') || ($name eq 'acc')) {
                   3765:                     my $stringtype = &get_stringtype($name);
                   3766:                     my $stringmatch = &standard_string_matches($stringtype);
                   3767:                     if (ref($stringmatch) eq 'ARRAY') {
                   3768:                         foreach my $item (@{$stringmatch}) {
                   3769:                             if (ref($item) eq 'ARRAY') {
                   3770:                                 my ($regexpname,$pattern) = @{$item};
                   3771:                                 if ($pattern ne '') {
                   3772:                                     if ($val =~ /$pattern/) {
                   3773:                                         $valmatch = $regexpname;
                   3774:                                         $val = '';
                   3775:                                         last;
                   3776:                                     }
                   3777:                                 }
                   3778:                             }
                   3779:                         }
                   3780:                     }
1.554     raeburn  3781:                 } elsif ($name eq 'interval') {
                   3782:                     my $intervaltype = &get_intervaltype($name);
                   3783:                     my $intervalmatch = &standard_interval_matches($intervaltype);
                   3784:                     if (ref($intervalmatch) eq 'ARRAY') {
                   3785:                         foreach my $item (@{$intervalmatch}) {
                   3786:                             if (ref($item) eq 'ARRAY') {
                   3787:                                 my ($regexpname,$pattern) = @{$item};
                   3788:                                 if ($pattern ne '') {
                   3789:                                     if ($val =~ /$pattern/) {
                   3790:                                         $valmatch = $regexpname;
                   3791:                                         $val = '';
                   3792:                                         last;
                   3793:                                     }
                   3794:                                 }
                   3795:                             }
                   3796:                         }
                   3797:                     }
1.533     raeburn  3798:                 }
1.504     raeburn  3799:                 $needsrelease =
1.557     raeburn  3800:                     $Apache::lonnet::needsrelease{"parameter:$name:$val:$valmatch:"};
1.504     raeburn  3801:                 if ($needsrelease) {
1.505     raeburn  3802:                     unless ($got_chostname) {
1.514     raeburn  3803:                         ($chostname,$cmajor,$cminor) = &parameter_release_vars();
1.504     raeburn  3804:                         $got_chostname = 1;
1.546     raeburn  3805:                     } 
1.557     raeburn  3806:                     $needsnewer = &parameter_releasecheck($name,$val,$valmatch,undef,
1.514     raeburn  3807:                                                           $needsrelease,
                   3808:                                                           $cmajor,$cminor);
1.500     raeburn  3809:                 }
1.437     raeburn  3810:             }
1.504     raeburn  3811:             if ($needsnewer) {
1.557     raeburn  3812:                 undef($namematch);
                   3813:             } else {
                   3814:                 my $currneeded;
                   3815:                 if ($needsrelease) {
                   3816:                     $currneeded = $needsrelease;
                   3817:                 }
                   3818:                 if ($namematch) {
                   3819:                     $needsrelease =
                   3820:                         $Apache::lonnet::needsrelease{"parameter::::$namematch"};
                   3821:                     if (($needsrelease) && (($currneeded eq '') || ($needsrelease < $currneeded))) {
                   3822:                         unless ($got_chostname) {
                   3823:                             ($chostname,$cmajor,$cminor) = &parameter_release_vars();
                   3824:                             $got_chostname = 1;
                   3825:                         }
                   3826:                         $needsnewer = &parameter_releasecheck(undef,undef,undef,$namematch,
                   3827:                                                               $needsrelease,
                   3828:                                                               $cmajor,$cminor);
                   3829:                     } else {
                   3830:                         undef($namematch);
                   3831:                     }
                   3832:                 }
                   3833:             }
                   3834:             if ($needsnewer) {
                   3835:                 $message .= &oldversion_warning($name,$namematch,$values[$i],$chostname,$cmajor,
1.504     raeburn  3836:                                                 $cminor,$needsrelease);
                   3837:             } else {
                   3838:                 $message.=&storeparm(split(/\&/,$markers[$i]),
                   3839:                                      $values[$i],
                   3840:                                      $types[$i],
                   3841:                                      $uname,$udom,$csec,$cgroup);
                   3842:                 $totalstored ++;
                   3843:             }
1.473     amueller 3844:         }
1.68      www      3845: # ---------------------------------------------------------------- Done storing
1.504     raeburn  3846:         if ($totalstored) {
                   3847:             $message.='<p class="LC_warning">'
1.605     raeburn  3848:                      .&mt('Changes for [quant,_1,parameter] saved.',$totalstored)
                   3849:                      .'<br />'
1.504     raeburn  3850:                      .&mt('Changes can take up to 10 minutes before being active for all students.')
                   3851:                      .&Apache::loncommon::help_open_topic('Caching')
                   3852:                      .'</p>';
1.605     raeburn  3853:         } else {
                   3854:             $message.='<p class="LC_info">'.&mt('No parameter changes saved.').'</p>';
                   3855:         }
                   3856:         if ($totalskippeduser) {
                   3857:             $message .= '<p class="LC_warning">';
                   3858:             if ($uhome eq 'no_host') {
                   3859:                 $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the username or ID was invalid.',
                   3860:                                 $totalskippeduser);
                   3861:             } elsif ($env{'form.userroles'} eq 'any') {
                   3862:                 $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user does not have a course role.',
                   3863:                                 $totalskippeduser);
                   3864:             } else {
                   3865:                 $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user is not a student.',
                   3866:                                 $totalskippeduser);
                   3867:             }
                   3868:             $message .= '</p>';
1.504     raeburn  3869:         }
1.68      www      3870:     }
1.584     raeburn  3871: 
1.57      albertel 3872: #----------------------------------------------- if all selected, fill in array
1.563     damieng  3873:     if ($pscat[0] eq "all") {
                   3874:         @pscat = (keys(%allparms));
                   3875:     }
                   3876:     if (!@pscat) {
                   3877:         @pscat=('duedate','opendate','answerdate','weight','maxtries','type','problemstatus')
                   3878:     };
                   3879:     if ($psprt[0] eq "all" || !@psprt) {
                   3880:         @psprt = (keys(%allparts));
                   3881:     }
1.2       www      3882: # ------------------------------------------------------------------ Start page
1.63      bowersj2 3883: 
1.531     raeburn  3884:     my $crstype = &Apache::loncommon::course_type();
                   3885:     &startpage($r,$pssymb,$crstype);
1.57      albertel 3886: 
1.548     raeburn  3887:     foreach my $item ('tolerance','date_default','date_start','date_end',
1.589     raeburn  3888:             'date_interval','int','float','string','string_lenient',
                   3889:             'string_examcode','string_deeplink','string_discussvote',
                   3890:             'string_useslots','string_problemstatus','string_ip',
1.622     raeburn  3891:             'string_questiontype','string_tex','string_grace') {
1.473     amueller 3892:         $r->print('<input type="hidden" value="'.
1.563     damieng  3893:             &HTML::Entities::encode($env{'form.recent_'.$item},'"&<>').
                   3894:             '" name="recent_'.$item.'" />');
1.44      albertel 3895:     }
1.446     bisitz   3896: 
1.459     bisitz   3897:     # ----- Start Parameter Selection
                   3898: 
1.606     raeburn  3899:     # Hide parm selection and possibly table?
                   3900:     my ($tablejs,$tabledivsty);
                   3901:     if (((($env{'form.uname'} ne '') || ($env{'form.id'} ne '')) && ($uname eq '')) &&
                   3902:         ($env{'form.dis'}) && ($pssymb eq '')) {
                   3903:         $tablejs = 'document.getElementById('."'parmtable'".').style.display = "";';
                   3904:         $tabledivsty = ' style="display:none"';
                   3905:     }
1.459     bisitz   3906:     $r->print(<<ENDPARMSELSCRIPT);
                   3907: <script type="text/javascript">
                   3908: // <![CDATA[
                   3909: function parmsel_show() {
1.562     damieng  3910:     document.getElementById('parmsel').style.display = "";
                   3911:     document.getElementById('parmsellink').style.display = "none";
1.606     raeburn  3912:     $tablejs
1.459     bisitz   3913: }
                   3914: // ]]>
                   3915: </script>
                   3916: ENDPARMSELSCRIPT
1.474     amueller 3917:     
1.445     neumanie 3918:     if (!$pssymb) {
1.563     damieng  3919:         # No single resource selected, print forms to select things (hidden after first selection)
1.486     www      3920:         my $parmselhiddenstyle=' style="display:none"';
                   3921:         if($env{'form.hideparmsel'} eq 'hidden') {
                   3922:            $r->print('<div id="parmsel"'.$parmselhiddenstyle.'>');
                   3923:         } else  {
                   3924:            $r->print('<div id="parmsel">');
                   3925:         }
                   3926: 
1.491     bisitz   3927:         # Step 1
1.523     raeburn  3928:         $r->print(&Apache::lonhtmlcommon::topic_bar(1,&mt('Resource Specification'),'parmstep1'));
                   3929:         $r->print('
1.474     amueller 3930: <script type="text/javascript">
1.523     raeburn  3931: // <![CDATA['.
                   3932:                  &showhide_js().'
1.474     amueller 3933: // ]]>
                   3934: </script>
1.523     raeburn  3935: ');
                   3936:         $r->print(&Apache::lonhtmlcommon::start_pick_box(undef,'parmlevel'));
1.209     www      3937:         &levelmenu($r,\%alllevs,$parmlev);
1.491     bisitz   3938:         $r->print(&Apache::lonhtmlcommon::row_closure());
1.610     raeburn  3939:         &mapmenu($r,\%allmaps,$pschp,\%maptitles,\%symbp,$parmlev);
1.491     bisitz   3940:         $r->print(&Apache::lonhtmlcommon::row_closure());
                   3941:         $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parts to View')));
                   3942:         &partmenu($r,\%allparts,\@psprt);
1.474     amueller 3943:         $r->print(&Apache::lonhtmlcommon::row_closure(1));
                   3944:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.491     bisitz   3945: 
                   3946:         # Step 2
1.523     raeburn  3947:         $r->print(&Apache::lonhtmlcommon::topic_bar(2,&mt('Parameter Specification'),'parmstep2'));
1.581     raeburn  3948:         &displaymenu($r,\%allparms,\@pscat,\%keyorder,'parmmenuscroll');
1.491     bisitz   3949: 
                   3950:         # Step 3
1.523     raeburn  3951:         $r->print(&Apache::lonhtmlcommon::topic_bar(3,&mt('User Specification (optional)'),'parmstep3'));
1.486     www      3952:         $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.553     raeburn  3953:         &usermenu($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,\@usersgroups,$pssymb);
1.486     www      3954:         $r->print(&Apache::lonhtmlcommon::row_closure(1));
                   3955:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.491     bisitz   3956: 
                   3957:         # Update Display Button
1.486     www      3958:         $r->print('<p>'
                   3959:              .'<input type="submit" name="dis"'
1.511     www      3960:              .' value="'.&mt('Update Display').'" />'
1.486     www      3961:              .'<input type="hidden" name="hideparmsel" value="hidden" />'
                   3962:              .'</p>');
                   3963:         $r->print('</div>');
1.491     bisitz   3964: 
1.486     www      3965:         # Offer link to display parameter selection again
                   3966:         $r->print('<p id="parmsellink"');
                   3967:         if ($env{'form.hideparmsel'} ne 'hidden') {
                   3968:            $r->print($parmselhiddenstyle);
                   3969:         }
                   3970:         $r->print('>'
                   3971:              .'<a href="javascript:parmsel_show()">'
                   3972:              .&mt('Change Parameter Selection')
                   3973:              .'</a>'
                   3974:              .'</p>');
1.44      albertel 3975:     } else {
1.478     amueller 3976:         # parameter screen for a single resource. 
1.486     www      3977:         my ($map,$iid,$resource)=&Apache::lonnet::decode_symb($pssymb);
1.473     amueller 3978:         my $title = &Apache::lonnet::gettitle($pssymb);
1.501     bisitz   3979:         $r->print(&mt('Specific Resource: [_1] ([_2])',
                   3980:                          $title,'<span class="LC_filename">'.$resource.'</span>').
1.472     amueller 3981:                 '<input type="hidden" value="'.$pssymb.'" name="symb" />'.
1.486     www      3982:                   '<br />');
                   3983:         $r->print(&Apache::lonhtmlcommon::topic_bar('',&mt('Additional Display Specification (optional)')));
                   3984:         $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.553     raeburn  3985:         &usermenu($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,\@usersgroups,$pssymb);
1.486     www      3986:         $r->print(&Apache::lonhtmlcommon::row_closure(1));
                   3987:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   3988:         $r->print('<p>'
1.459     bisitz   3989:              .'<input type="submit" name="dis"'
1.511     www      3990:              .' value="'.&mt('Update Display').'" />'
1.459     bisitz   3991:              .'<input type="hidden" name="hideparmsel" value="hidden" />'
1.486     www      3992:              .'</p>');
1.459     bisitz   3993:     }
1.478     amueller 3994:     
1.486     www      3995:     # ----- End Parameter Selection
1.57      albertel 3996: 
1.459     bisitz   3997:     # Display Messages
                   3998:     $r->print('<div>'.$message.'</div>');
1.210     www      3999: 
1.57      albertel 4000: 
                   4001:     my @temp_pscat;
                   4002:     map {
                   4003:         my $cat = $_;
                   4004:         push(@temp_pscat, map { $_.'.'.$cat } @psprt);
                   4005:     } @pscat;
                   4006: 
                   4007:     @pscat = @temp_pscat;
                   4008: 
1.548     raeburn  4009: 
1.209     www      4010:     if (($env{'form.prevvisit'}) || ($pschp) || ($pssymb)) {
1.10      www      4011: # ----------------------------------------------------------------- Start Table
1.57      albertel 4012:         my @catmarker=map { tr|.|_|; 'parameter_'.$_; } @pscat;
1.190     albertel 4013:         my $csuname=$env{'user.name'};
                   4014:         my $csudom=$env{'user.domain'};
1.568     raeburn  4015:         my $readonly = 1;
                   4016:         if ($parm_permission->{'edit'}) {
                   4017:             undef($readonly); 
                   4018:         }
1.606     raeburn  4019:         $r->print('<div id="parmtable"'.$tabledivsty.'>');
1.57      albertel 4020: 
1.203     www      4021:         if ($parmlev eq 'full') {
1.506     www      4022: #
                   4023: # This produces the cascading table output of parameters
                   4024: #
1.578     raeburn  4025:             my $coursespan=$csec?8:5;
                   4026:             my $userspan=3;
1.560     damieng  4027:             if ($cgroup ne '') {
1.578     raeburn  4028:                 $coursespan += 3;
1.560     damieng  4029:             }
1.473     amueller 4030: 
1.560     damieng  4031:             $r->print(&Apache::loncommon::start_data_table());
                   4032:             #
                   4033:             # This produces the headers
                   4034:             #
                   4035:             $r->print('<tr><td colspan="5"></td>');
                   4036:             $r->print('<th colspan="'.($coursespan).'">'.&mt('Any User').'</th>');
                   4037:             if ($uname) {
1.473     amueller 4038:                 if (@usersgroups > 1) {
1.560     damieng  4039:                     $userspan ++;
                   4040:                 }
                   4041:                 $r->print('<th colspan="'.$userspan.'" rowspan="2">');
                   4042:                 $r->print(&mt('User [_1] at Domain [_2]',"'".$uname."'","'".$udom."'").'</th>');
                   4043:             }
                   4044:             my %lt=&Apache::lonlocal::texthash(
1.473     amueller 4045:                 'pie'    => "Parameter in Effect",
                   4046:                 'csv'    => "Current Session Value",
1.472     amueller 4047:                 'rl'     => "Resource Level",
1.473     amueller 4048:                 'ic'     => 'in Course',
                   4049:                 'aut'    => "Assessment URL and Title",
                   4050:                 'type'   => 'Type',
                   4051:                 'emof'   => "Enclosing Map or Folder",
                   4052:                 'part'   => 'Part',
1.472     amueller 4053:                 'pn'     => 'Parameter Name',
1.473     amueller 4054:                 'def'    => 'default',
                   4055:                 'femof'  => 'from Enclosing Map or Folder',
                   4056:                 'gen'    => 'general',
                   4057:                 'foremf' => 'for Enclosing Map or Folder',
                   4058:                 'fr'     => 'for Resource'
                   4059:             );
1.560     damieng  4060:             $r->print(<<ENDTABLETWO);
1.419     bisitz   4061: <th rowspan="3">$lt{'pie'}</th>
1.501     bisitz   4062: <th rowspan="3">$lt{'csv'}<br />($csuname:$csudom)</th>
1.578     raeburn  4063: </tr><tr><td colspan="5"></td><th colspan="2">$lt{'ic'}</th><th colspan="2">$lt{'rl'}</th>
1.419     bisitz   4064: <th colspan="1">$lt{'ic'}</th>
1.182     albertel 4065: 
1.10      www      4066: ENDTABLETWO
1.560     damieng  4067:             if ($csec) {
1.578     raeburn  4068:                 $r->print('<th colspan="3">'.
1.560     damieng  4069:                 &mt("in Section")." $csec</th>");
                   4070:             }
                   4071:             if ($cgroup) {
1.578     raeburn  4072:                 $r->print('<th colspan="3">'.
1.472     amueller 4073:                 &mt("in Group")." $cgroup</th>");
1.560     damieng  4074:             }
                   4075:             $r->print(<<ENDTABLEHEADFOUR);
1.133     www      4076: </tr><tr><th>$lt{'aut'}</th><th>$lt{'type'}</th>
                   4077: <th>$lt{'emof'}</th><th>$lt{'part'}</th><th>$lt{'pn'}</th>
1.578     raeburn  4078: <th>$lt{'gen'}</th><th>$lt{'foremf'}</th>
1.192     albertel 4079: <th>$lt{'def'}</th><th>$lt{'femof'}</th><th>$lt{'fr'}</th>
1.10      www      4080: ENDTABLEHEADFOUR
1.57      albertel 4081: 
1.560     damieng  4082:             if ($csec) {
1.578     raeburn  4083:                 $r->print('<th>'.$lt{'gen'}.'</th><th>'.$lt{'foremf'}.'</th><th>'.$lt{'fr'}.'</th>');
1.560     damieng  4084:             }
1.473     amueller 4085: 
1.560     damieng  4086:             if ($cgroup) {
1.578     raeburn  4087:                 $r->print('<th>'.$lt{'gen'}.'</th><th>'.$lt{'foremf'}.'</th><th>'.$lt{'fr'}.'</th>');
1.560     damieng  4088:             }
                   4089: 
                   4090:             if ($uname) {
                   4091:                 if (@usersgroups > 1) {
                   4092:                     $r->print('<th>'.&mt('Control by other group?').'</th>');
                   4093:                 }
1.578     raeburn  4094:                 $r->print('<th>'.$lt{'gen'}.'</th><th>'.$lt{'foremf'}.'</th><th>'.$lt{'fr'}.'</th>');
1.560     damieng  4095:             }
                   4096: 
                   4097:             $r->print('</tr>');
1.506     www      4098: #
                   4099: # Done with the headers
                   4100: # 
1.560     damieng  4101:             my $defbgone='';
                   4102:             my $defbgtwo='';
                   4103:             my $defbgthree = '';
1.57      albertel 4104: 
1.560     damieng  4105:             foreach my $rid (@ids) {
1.57      albertel 4106: 
                   4107:                 my ($inmapid)=($rid=~/\.(\d+)$/);
1.446     bisitz   4108:                 if ((!$pssymb &&
1.560     damieng  4109:                         (($pschp eq 'all') || ($allmaps{$pschp} eq $mapp{$rid})))
                   4110:                         ||
                   4111:                         ($pssymb && $pssymb eq $symbp{$rid})) {
1.4       www      4112: # ------------------------------------------------------ Entry for one resource
1.473     amueller 4113:                     if ($defbgone eq '#E0E099') {
                   4114:                         $defbgone='#E0E0DD';
1.57      albertel 4115:                     } else {
1.419     bisitz   4116:                         $defbgone='#E0E099';
1.57      albertel 4117:                     }
1.419     bisitz   4118:                     if ($defbgtwo eq '#FFFF99') {
1.473     amueller 4119:                         $defbgtwo='#FFFFDD';
1.57      albertel 4120:                     } else {
1.473     amueller 4121:                         $defbgtwo='#FFFF99';
1.57      albertel 4122:                     }
1.419     bisitz   4123:                     if ($defbgthree eq '#FFBB99') {
                   4124:                         $defbgthree='#FFBBDD';
1.269     raeburn  4125:                     } else {
1.419     bisitz   4126:                         $defbgthree='#FFBB99';
1.269     raeburn  4127:                     }
                   4128: 
1.57      albertel 4129:                     my $thistitle='';
                   4130:                     my %name=   ();
                   4131:                     undef %name;
                   4132:                     my %part=   ();
                   4133:                     my %display=();
                   4134:                     my %type=   ();
                   4135:                     my %default=();
1.196     www      4136:                     my $uri=&Apache::lonnet::declutter($uris{$rid});
1.584     raeburn  4137:                     my $toolsymb;
                   4138:                     if ($uri =~ /ext\.tool$/) {
                   4139:                         $toolsymb = $symbp{$rid};
                   4140:                     }
1.57      albertel 4141: 
1.506     www      4142:                     my $filter=$env{'form.filter'};
1.548     raeburn  4143:                     foreach my $tempkeyp (&keysplit($keyp{$rid})) {
1.57      albertel 4144:                         if (grep $_ eq $tempkeyp, @catmarker) {
1.584     raeburn  4145:                             my $parmname=&Apache::lonnet::metadata($uri,$tempkeyp.'.name',$toolsymb);
1.560     damieng  4146:     # We may only want certain parameters listed
                   4147:                             if ($filter) {
                   4148:                                 unless ($filter=~/\Q$parmname\E/) { next; }
                   4149:                             }
                   4150:                             $name{$tempkeyp}=$parmname;
1.584     raeburn  4151:                             $part{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.part',$toolsymb);
1.560     damieng  4152: 
1.584     raeburn  4153:                             my $parmdis=&Apache::lonnet::metadata($uri,$tempkeyp.'.display',$toolsymb);
1.560     damieng  4154:                             if ($allparms{$name{$tempkeyp}} ne '') {
                   4155:                                 my $identifier;
                   4156:                                 if ($parmdis =~ /(\s*\[Part.*)$/) {
                   4157:                                     $identifier = $1;
                   4158:                                 }
                   4159:                                 $display{$tempkeyp} = $allparms{$name{$tempkeyp}}.$identifier;
                   4160:                             } else {
                   4161:                                 $display{$tempkeyp} = $parmdis;
                   4162:                             }
                   4163:                             unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; }
                   4164:                             $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')';
1.584     raeburn  4165:                             $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp,$toolsymb);
                   4166:                             $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.type',$toolsymb);
                   4167:                             $thistitle=&Apache::lonnet::metadata($uri,$tempkeyp.'.title',$toolsymb);
1.57      albertel 4168:                         }
                   4169:                     }
1.548     raeburn  4170:                     my $totalparms=scalar(keys(%name));
1.57      albertel 4171:                     if ($totalparms>0) {
1.560     damieng  4172:                         my $firstrow=1;
1.473     amueller 4173:                         my $title=&Apache::lonnet::gettitle($symbp{$rid});
1.582     raeburn  4174:                         my $navmap = Apache::lonnavmaps::navmap->new();
                   4175:                         my @recurseup;
                   4176:                         if (ref($navmap) && $mapp{$rid}) {
                   4177:                             @recurseup = $navmap->recurseup_maps($mapp{$rid});
                   4178:                         }
1.419     bisitz   4179:                         $r->print('<tr><td style="background-color:'.$defbgone.';"'.
1.57      albertel 4180:                              ' rowspan='.$totalparms.
1.419     bisitz   4181:                              '><tt><font size="-1">'.
1.57      albertel 4182:                              join(' / ',split(/\//,$uri)).
                   4183:                              '</font></tt><p><b>'.
1.154     albertel 4184:                              "<a href=\"javascript:openWindow('".
1.473     amueller 4185:                           &Apache::lonnet::clutter($uri).'?symb='.
                   4186:                           &escape($symbp{$rid}).
1.336     albertel 4187:                              "', 'metadatafile', '450', '500', 'no', 'yes');\"".
                   4188:                              " target=\"_self\">$title");
1.57      albertel 4189: 
                   4190:                         if ($thistitle) {
1.473     amueller 4191:                             $r->print(' ('.$thistitle.')');
1.57      albertel 4192:                         }
                   4193:                         $r->print('</a></b></td>');
1.419     bisitz   4194:                         $r->print('<td style="background-color:'.$defbgtwo.';"'.
1.57      albertel 4195:                                       ' rowspan='.$totalparms.'>'.$typep{$rid}.
                   4196:                                       '</td>');
                   4197: 
1.419     bisitz   4198:                         $r->print('<td style="background-color:'.$defbgone.';"'.
1.57      albertel 4199:                                       ' rowspan='.$totalparms.
1.238     www      4200:                                       '>'.$maptitles{$mapp{$rid}}.'</td>');
1.548     raeburn  4201:                         foreach my $item (&keysinorder_bytype(\%name,\%keyorder)) {
1.57      albertel 4202:                             unless ($firstrow) {
                   4203:                                 $r->print('<tr>');
                   4204:                             } else {
                   4205:                                 undef $firstrow;
                   4206:                             }
1.548     raeburn  4207:                             &print_row($r,$item,\%part,\%name,\%symbp,$rid,\%default,
1.57      albertel 4208:                                        \%type,\%display,$defbgone,$defbgtwo,
1.269     raeburn  4209:                                        $defbgthree,$parmlev,$uname,$udom,$csec,
1.582     raeburn  4210:                                        $cgroup,\@usersgroups,$noeditgrp,$readonly,
                   4211:                                        \@recurseup,\%maptitles,\%allmaps_inverted,
                   4212:                                        \$numreclinks);
1.57      albertel 4213:                         }
                   4214:                     }
                   4215:                 }
                   4216:             } # end foreach ids
1.43      albertel 4217: # -------------------------------------------------- End entry for one resource
1.517     www      4218:             $r->print(&Apache::loncommon::end_data_table);
1.203     www      4219:         } # end of  full
1.57      albertel 4220: #--------------------------------------------------- Entry for parm level map
                   4221:         if ($parmlev eq 'map') {
1.419     bisitz   4222:             my $defbgone = '#E0E099';
                   4223:             my $defbgtwo = '#FFFF99';
                   4224:             my $defbgthree = '#FFBB99';
1.57      albertel 4225: 
                   4226:             my %maplist;
                   4227: 
                   4228:             if ($pschp eq 'all') {
1.446     bisitz   4229:                 %maplist = %allmaps;
1.57      albertel 4230:             } else {
                   4231:                 %maplist = ($pschp => $mapp{$pschp});
                   4232:             }
                   4233: 
                   4234: #-------------------------------------------- for each map, gather information
                   4235:             my $mapid;
1.607     raeburn  4236:             foreach $mapid (sort { $a <=> $b } keys(%maplist)) {
1.60      albertel 4237:                 my $maptitle = $maplist{$mapid};
1.57      albertel 4238: 
                   4239: #-----------------------  loop through ids and get all parameter types for map
                   4240: #-----------------------------------------          and associated information
                   4241:                 my %name = ();
                   4242:                 my %part = ();
                   4243:                 my %display = ();
                   4244:                 my %type = ();
                   4245:                 my %default = ();
                   4246:                 my $map = 0;
                   4247: 
1.473     amueller 4248: #        $r->print("Catmarker: @catmarker<br />\n");
1.446     bisitz   4249: 
1.548     raeburn  4250:                 foreach my $id (@ids) {
                   4251:                     ($map)=($id =~ /([\d]*?)\./);
                   4252:                     my $rid = $id;
1.446     bisitz   4253: 
1.57      albertel 4254: #                  $r->print("$mapid:$map:   $rid <br /> \n");
                   4255: 
1.560     damieng  4256:                     if ($map eq $mapid) {
1.473     amueller 4257:                         my $uri=&Apache::lonnet::declutter($uris{$rid});
1.584     raeburn  4258:                         my $toolsymb;
                   4259:                         if ($uri =~ /ext\.tool$/) {
                   4260:                             $toolsymb = $symbp{$rid};
                   4261:                         }
1.582     raeburn  4262: 
1.57      albertel 4263: #                    $r->print("Keys: $keyp{$rid} <br />\n");
                   4264: 
                   4265: #--------------------------------------------------------------------
                   4266: # @catmarker contains list of all possible parameters including part #s
                   4267: # $fullkeyp contains the full part/id # for the extraction of proper parameters
                   4268: # $tempkeyp contains part 0 only (no ids - ie, subparts)
                   4269: # When storing information, store as part 0
                   4270: # When requesting information, request from full part
                   4271: #-------------------------------------------------------------------
1.548     raeburn  4272:                         foreach my $fullkeyp (&keysplit($keyp{$rid})) {
                   4273:                             my $tempkeyp = $fullkeyp;
                   4274:                             $tempkeyp =~ s/_\w+_/_0_/;
1.473     amueller 4275: 
1.548     raeburn  4276:                             if ((grep $_ eq $fullkeyp, @catmarker) &&(!$name{$tempkeyp})) {
1.473     amueller 4277:                                 $part{$tempkeyp}="0";
1.584     raeburn  4278:                                 $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name',$toolsymb);
                   4279:                                 my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display',$toolsymb);
1.473     amueller 4280:                                 if ($allparms{$name{$tempkeyp}} ne '') {
                   4281:                                     my $identifier;
                   4282:                                     if ($parmdis =~ /(\s*\[Part.*)$/) {
                   4283:                                         $identifier = $1;
                   4284:                                     }
                   4285:                                     $display{$tempkeyp} = $allparms{$name{$tempkeyp}}.$identifier;
                   4286:                                 } else {
                   4287:                                     $display{$tempkeyp} = $parmdis;
                   4288:                                 }
                   4289:                                 unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; }
                   4290:                                 $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')';
                   4291:                                 $display{$tempkeyp} =~ s/_\w+_/_0_/;
1.584     raeburn  4292:                                 $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp,$toolsymb);
                   4293:                                 $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type',$toolsymb);
1.473     amueller 4294:                               }
                   4295:                         } # end loop through keys
1.560     damieng  4296:                     }
1.57      albertel 4297:                 } # end loop through ids
1.446     bisitz   4298: 
1.57      albertel 4299: #---------------------------------------------------- print header information
1.133     www      4300:                 my $foldermap=&mt($maptitle=~/^uploaded/?'Folder':'Map');
1.82      www      4301:                 my $showtitle=$maptitles{$maptitle}.($maptitle!~/^uploaded/?' ['.$maptitle.']':'');
1.401     bisitz   4302:                 my $tmp="";
1.57      albertel 4303:                 if ($uname) {
1.473     amueller 4304:                     my $person=&Apache::loncommon::plainname($uname,$udom);
1.401     bisitz   4305:                     $tmp.=&mt("User")." <font color=\"red\"><i>$uname \($person\) </i></font> ".
                   4306:                         &mt('in')." \n";
1.57      albertel 4307:                 } else {
1.401     bisitz   4308:                     $tmp.="<font color=\"red\"><i>".&mt('all').'</i></font> '.&mt('users in')." \n";
1.57      albertel 4309:                 }
1.269     raeburn  4310:                 if ($cgroup) {
1.401     bisitz   4311:                     $tmp.=&mt("Group")." <font color=\"red\"><i>$cgroup".
                   4312:                               "</i></font> ".&mt('of')." \n";
1.269     raeburn  4313:                     $csec = '';
                   4314:                 } elsif ($csec) {
1.401     bisitz   4315:                     $tmp.=&mt("Section")." <font color=\"red\"><i>$csec".
                   4316:                               "</i></font> ".&mt('of')." \n";
1.269     raeburn  4317:                 }
1.401     bisitz   4318:                 $r->print('<div align="center"><h4>'
                   4319:                          .&mt('Set Defaults for All Resources in [_1]Specifically for [_2][_3]'
1.404     bisitz   4320:                              ,$foldermap.'<br /><font color="red"><i>'.$showtitle.'</i></font><br />'
1.401     bisitz   4321:                              ,$tmp
                   4322:                              ,'<font color="red"><i>'.$coursename.'</i></font>'
                   4323:                              )
                   4324:                          ."<br /></h4>\n"
1.422     bisitz   4325:                 );
1.57      albertel 4326: #---------------------------------------------------------------- print table
1.419     bisitz   4327:                 $r->print('<p>'.&Apache::loncommon::start_data_table()
                   4328:                          .&Apache::loncommon::start_data_table_header_row()
                   4329:                          .'<th>'.&mt('Parameter Name').'</th>'
1.578     raeburn  4330:                          .'<th>'.&mt('Value').'</th>'
1.419     bisitz   4331:                          .'<th>'.&mt('Parameter in Effect').'</th>'
                   4332:                          .&Apache::loncommon::end_data_table_header_row()
                   4333:                 );
1.57      albertel 4334: 
1.582     raeburn  4335:                 my $navmap = Apache::lonnavmaps::navmap->new();
                   4336:                 my @recurseup;
                   4337:                 if (ref($navmap)) {
                   4338:                      my $mapres = $navmap->getByMapPc($mapid);
                   4339:                      if (ref($mapres)) {
                   4340:                          @recurseup = $navmap->recurseup_maps($mapres->src());
                   4341:                      }
                   4342:                 }
                   4343: 
                   4344: 
1.548     raeburn  4345:                 foreach my $item (&keysinorder(\%name,\%keyorder)) {
1.473     amueller 4346:                     $r->print(&Apache::loncommon::start_data_table_row());
1.548     raeburn  4347:                     &print_row($r,$item,\%part,\%name,\%symbp,$mapid,\%default,
1.269     raeburn  4348:                            \%type,\%display,$defbgone,$defbgtwo,$defbgthree,
1.568     raeburn  4349:                            $parmlev,$uname,$udom,$csec,$cgroup,'',$noeditgrp,
1.582     raeburn  4350:                            $readonly,\@recurseup,\%maptitles,\%allmaps_inverted,
                   4351:                            \$numreclinks);
1.57      albertel 4352:                 }
1.422     bisitz   4353:                 $r->print(&Apache::loncommon::end_data_table().'</p>'
                   4354:                          .'</div>'
                   4355:                 );
1.57      albertel 4356:             } # end each map
                   4357:         } # end of $parmlev eq map
                   4358: #--------------------------------- Entry for parm level general (Course level)
                   4359:         if ($parmlev eq 'general') {
1.473     amueller 4360:             my $defbgone = '#E0E099';
1.419     bisitz   4361:             my $defbgtwo = '#FFFF99';
                   4362:             my $defbgthree = '#FFBB99';
1.57      albertel 4363: 
                   4364: #-------------------------------------------- for each map, gather information
                   4365:             my $mapid="0.0";
                   4366: #-----------------------  loop through ids and get all parameter types for map
                   4367: #-----------------------------------------          and associated information
                   4368:             my %name = ();
                   4369:             my %part = ();
                   4370:             my %display = ();
                   4371:             my %type = ();
                   4372:             my %default = ();
1.446     bisitz   4373: 
1.548     raeburn  4374:             foreach $id (@ids) {
                   4375:                 my $rid = $id;
1.446     bisitz   4376: 
1.196     www      4377:                 my $uri=&Apache::lonnet::declutter($uris{$rid});
1.584     raeburn  4378:                 my $toolsymb;
                   4379:                 if ($uri =~ /ext\.tool$/) {
                   4380:                     $toolsymb = $symbp{$rid};
                   4381:                 }
1.57      albertel 4382: 
                   4383: #--------------------------------------------------------------------
                   4384: # @catmarker contains list of all possible parameters including part #s
                   4385: # $fullkeyp contains the full part/id # for the extraction of proper parameters
                   4386: # $tempkeyp contains part 0 only (no ids - ie, subparts)
                   4387: # When storing information, store as part 0
                   4388: # When requesting information, request from full part
                   4389: #-------------------------------------------------------------------
1.548     raeburn  4390:                 foreach my $fullkeyp (&keysplit($keyp{$rid})) {
                   4391:                     my $tempkeyp = $fullkeyp;
                   4392:                     $tempkeyp =~ s/_\w+_/_0_/;
                   4393:                     if ((grep $_ eq $fullkeyp, @catmarker) &&(!$name{$tempkeyp})) {
1.473     amueller 4394:                         $part{$tempkeyp}="0";
1.584     raeburn  4395:                         $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name',$toolsymb);
                   4396:                         my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display',$toolsymb);
1.473     amueller 4397:                         if ($allparms{$name{$tempkeyp}} ne '') {
                   4398:                             my $identifier;
                   4399:                             if ($parmdis =~ /(\s*\[Part.*)$/) {
                   4400:                                 $identifier = $1;
                   4401:                             }
                   4402:                             $display{$tempkeyp} = $allparms{$name{$tempkeyp}}.$identifier;
                   4403:                         } else {
                   4404:                             $display{$tempkeyp} = $parmdis;
                   4405:                         }
                   4406:                         unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; }
                   4407:                         $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')';
                   4408:                         $display{$tempkeyp} =~ s/_\w+_/_0_/;
1.584     raeburn  4409:                         $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp,$toolsymb);
                   4410:                         $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type',$toolsymb);
1.560     damieng  4411:                     }
1.57      albertel 4412:                 } # end loop through keys
                   4413:             } # end loop through ids
1.446     bisitz   4414: 
1.57      albertel 4415: #---------------------------------------------------- print header information
1.473     amueller 4416:             my $setdef=&mt("Set Defaults for All Resources in Course");
1.57      albertel 4417:             $r->print(<<ENDMAPONE);
1.419     bisitz   4418: <center>
                   4419: <h4>$setdef
1.135     albertel 4420: <font color="red"><i>$coursename</i></font><br />
1.57      albertel 4421: ENDMAPONE
                   4422:             if ($uname) {
1.473     amueller 4423:                 my $person=&Apache::loncommon::plainname($uname,$udom);
1.135     albertel 4424:                 $r->print(" ".&mt("User")."<font color=\"red\"> <i>$uname \($person\) </i></font> \n");
1.57      albertel 4425:             } else {
1.135     albertel 4426:                 $r->print("<i><font color=\"red\"> ".&mt("ALL")."</i> ".&mt("USERS")."</font> \n");
1.57      albertel 4427:             }
1.446     bisitz   4428: 
1.135     albertel 4429:             if ($csec) {$r->print(&mt("Section")."<font color=\"red\"> <i>$csec</i></font>\n")};
1.306     albertel 4430:             if ($cgroup) {$r->print(&mt("Group")."<font color=\"red\"> <i>$cgroup</i></font>\n")};
1.135     albertel 4431:             $r->print("</h4>\n");
1.57      albertel 4432: #---------------------------------------------------------------- print table
1.419     bisitz   4433:             $r->print('<p>'.&Apache::loncommon::start_data_table()
                   4434:                      .&Apache::loncommon::start_data_table_header_row()
                   4435:                      .'<th>'.&mt('Parameter Name').'</th>'
                   4436:                      .'<th>'.&mt('Default Value').'</th>'
                   4437:                      .'<th>'.&mt('Parameter in Effect').'</th>'
                   4438:                      .&Apache::loncommon::end_data_table_header_row()
                   4439:             );
1.57      albertel 4440: 
1.548     raeburn  4441:             foreach my $item (&keysinorder(\%name,\%keyorder)) {
1.419     bisitz   4442:                 $r->print(&Apache::loncommon::start_data_table_row());
1.548     raeburn  4443:                 &print_row($r,$item,\%part,\%name,\%symbp,$mapid,\%default,
1.568     raeburn  4444:                            \%type,\%display,$defbgone,$defbgtwo,$defbgthree,
                   4445:                            $parmlev,$uname,$udom,$csec,$cgroup,'',$noeditgrp,
                   4446:                            $readonly);
1.57      albertel 4447:             }
1.419     bisitz   4448:             $r->print(&Apache::loncommon::end_data_table()
                   4449:                      .'</p>'
                   4450:                      .'</center>'
                   4451:             );
1.57      albertel 4452:         } # end of $parmlev eq general
1.606     raeburn  4453:         $r->print('</div>');
1.43      albertel 4454:     }
1.507     www      4455:     $r->print('</form>');
1.582     raeburn  4456:     if ($numreclinks) {
                   4457:         $r->print(<<"END");
                   4458: <form name="recurseform" action="/adm/parmset?action=settable" method="post">
                   4459: <input type="hidden" name="pschp" />
                   4460: <input type="hidden" name="pscat" />
                   4461: <input type="hidden" name="psprt" />
                   4462: <input type="hidden" name="hideparmsel" value="hidden" />
                   4463: </form>
                   4464: <script type="text/javascript">
                   4465: function pjumprec(rid,name,part) {
                   4466:     document.forms.recurseform.pschp.value = rid;
                   4467:     document.forms.recurseform.pscat.value = name;
                   4468:     document.forms.recurseform.psprt.value = part;
                   4469:     document.forms.recurseform.submit();
                   4470:     return false;
                   4471: }
                   4472: </script>
                   4473: END
                   4474:     }
1.507     www      4475:     &endSettingsScreen($r);
                   4476:     $r->print(&Apache::loncommon::end_page());
1.57      albertel 4477: } # end sub assessparms
1.30      www      4478: 
1.560     damieng  4479: 
                   4480: 
1.120     www      4481: ##################################################
1.560     damieng  4482: # OVERVIEW MODE
1.207     www      4483: ##################################################
1.124     www      4484: 
1.563     damieng  4485: my $tableopen; # boolean, true if HTML table is already opened
                   4486: 
                   4487: # Returns HTML with the HTML table start tag and header, unless the table is already opened.
                   4488: # @param {boolean} $readonly - true if values cannot be edited (otherwise more columns are added)
                   4489: # @returns {string}
1.124     www      4490: sub tablestart {
1.576     raeburn  4491:     my ($readonly,$is_map) = @_;
1.124     www      4492:     if ($tableopen) {
1.552     raeburn  4493:         return '';
1.124     www      4494:     } else {
1.552     raeburn  4495:         $tableopen=1;
                   4496:         my $output = &Apache::loncommon::start_data_table().'<tr><th>'.&mt('Parameter').'</th>';
                   4497:         if ($readonly) {
                   4498:             $output .= '<th>'.&mt('Current value').'</th>';
                   4499:         } else {
1.576     raeburn  4500:             $output .= '<th>'.&mt('Delete').'</th>'.
                   4501:                        '<th>'.&mt('Set to ...').'</th>';
                   4502:             if ($is_map) {
                   4503:                 $output .= '<th>'.&mt('Recursive?').'</th>';
                   4504:             }
1.552     raeburn  4505:         }
                   4506:         $output .= '</tr>';
                   4507:         return $output;
1.124     www      4508:     }
                   4509: }
                   4510: 
1.563     damieng  4511: # Returns HTML with the HTML table end tag, unless the table is not opened.
                   4512: # @returns {string}
1.124     www      4513: sub tableend {
                   4514:     if ($tableopen) {
1.560     damieng  4515:         $tableopen=0;
                   4516:         return &Apache::loncommon::end_data_table();
1.124     www      4517:     } else {
1.560     damieng  4518:         return'';
1.124     www      4519:     }
                   4520: }
                   4521: 
1.563     damieng  4522: # Reads course and user information.
                   4523: # 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).
                   4524: # The key for student data is modified with '[useropt:'.username.':'.userdomain.'].'.
                   4525: # If the context is looking for a list, returns a list with the scalar data and the class list.
                   4526: # @param {string} $crs - course number
                   4527: # @param {string} $dom - course domain
                   4528: # @returns {hash reference|Array}
1.207     www      4529: sub readdata {
                   4530:     my ($crs,$dom)=@_;
                   4531: # Read coursedata
                   4532:     my $resourcedata=&Apache::lonnet::get_courseresdata($crs,$dom);
                   4533: # Read userdata
                   4534: 
                   4535:     my $classlist=&Apache::loncoursedata::get_classlist();
1.548     raeburn  4536:     foreach my $user (keys(%$classlist)) {
                   4537:         if ($user=~/^($match_username)\:($match_domain)$/) {
                   4538:             my ($tuname,$tudom)=($1,$2);
                   4539:             my $useropt=&Apache::lonnet::get_userresdata($tuname,$tudom);
                   4540:             foreach my $userkey (keys(%{$useropt})) {
                   4541:                 if ($userkey=~/^\Q$env{'request.course.id'}\E/) {
1.207     www      4542:                     my $newkey=$userkey;
1.548     raeburn  4543:                     $newkey=~s/^($env{'request.course.id'}\.)/$1\[useropt\:$tuname\:$tudom\]\./;
                   4544:                     $$resourcedata{$newkey}=$$useropt{$userkey};
                   4545:                 }
                   4546:             }
1.473     amueller 4547:         }
                   4548:     }
1.552     raeburn  4549:     if (wantarray) {
                   4550:         return ($resourcedata,$classlist);
                   4551:     } else {
                   4552:         return $resourcedata;
                   4553:     }
1.207     www      4554: }
                   4555: 
                   4556: 
1.563     damieng  4557: # Stores parameter data, using form parameters directly.
                   4558: #
                   4559: # 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  4560: # set_* (except settext, setipallow, setipdeny, setdeeplink, setgrace) - set a parameter value
1.563     damieng  4561: # del_* - remove a parameter
                   4562: # datepointer_* - set a date parameter (value is key_* refering to a set of other form parameters)
                   4563: # dateinterval_* - set a date interval parameter (value refers to more form parameters)
                   4564: # key_* - date values
                   4565: # days_* - for date intervals
                   4566: # hours_* - for date intervals
                   4567: # minutes_* - for date intervals
                   4568: # seconds_* - for date intervals
                   4569: # done_* - for date intervals
                   4570: # typeof_* - parameter type
                   4571: # 
                   4572: # @param {Apache2::RequestRec} $r - the Apache request
                   4573: # @param {string} $crs - course number
                   4574: # @param {string} $dom - course domain
1.208     www      4575: sub storedata {
                   4576:     my ($r,$crs,$dom)=@_;
1.207     www      4577: # Set userlevel immediately
                   4578: # Do an intermediate store of course level
                   4579:     my $olddata=&readdata($crs,$dom);
1.124     www      4580:     my %newdata=();
                   4581:     undef %newdata;
                   4582:     my @deldata=();
1.576     raeburn  4583:     my @delrec=();
                   4584:     my @delnonrec=();
1.124     www      4585:     undef @deldata;
1.504     raeburn  4586:     my ($got_chostname,$chostname,$cmajor,$cminor);
1.546     raeburn  4587:     my $now = time;
1.560     damieng  4588:     foreach my $key (keys(%env)) {
                   4589:         if ($key =~ /^form\.([a-z]+)\_(.+)$/) {
                   4590:             my $cmd=$1;
                   4591:             my $thiskey=$2;
1.576     raeburn  4592:             my ($altkey,$recursive,$tkey,$tkeyrec,$tkeynonrec);
1.622     raeburn  4593:             next if ($cmd eq 'rec' || $cmd eq 'settext' || $cmd eq 'setipallow' || $cmd eq 'setipdeny' || $cmd eq 'setdeeplink' || $cmd eq 'setgrace');
1.576     raeburn  4594:             if ((($cmd eq 'set') || ($cmd eq 'datepointer') || ($cmd eq 'dateinterval') || ($cmd eq 'del')) && 
                   4595:                  ($thiskey =~ /(?:sequence|page)\Q___(all)\E/)) {
                   4596:                 unless ($thiskey =~ /(encrypturl|hiddenresource)$/) {
                   4597:                     $altkey = $thiskey;
                   4598:                     $altkey =~ s/\Q___(all)\E/___(rec)/;
                   4599:                     if ($env{'form.rec_'.$thiskey}) {
                   4600:                         $recursive = 1;
                   4601:                     }
                   4602:                 }
                   4603:             }
1.560     damieng  4604:             my ($tuname,$tudom)=&extractuser($thiskey);
1.473     amueller 4605:             if ($tuname) {
1.576     raeburn  4606:                 $tkey=$thiskey;
1.560     damieng  4607:                 $tkey=~s/\.\[useropt\:$tuname\:$tudom\]\./\./;
1.576     raeburn  4608:                 if ($altkey) {
                   4609:                     $tkeynonrec = $tkey; 
                   4610:                     $tkeyrec = $altkey;
                   4611:                     $tkeyrec=~s/\.\[useropt\:$tuname\:$tudom\]\./\./;
                   4612:                 }
1.560     damieng  4613:             }
                   4614:             if ($cmd eq 'set' || $cmd eq 'datepointer' || $cmd eq 'dateinterval') {
1.563     damieng  4615:                 my ($data, $typeof, $text, $name, $valchk, $valmatch, $namematch);
                   4616:                 if ($cmd eq 'set') {
                   4617:                     $data=$env{$key};
                   4618:                     $valmatch = '';
                   4619:                     $valchk = $data;
                   4620:                     $typeof=$env{'form.typeof_'.$thiskey};
                   4621:                     $text = &mt('Saved modified parameter for');
                   4622:                     if ($typeof eq 'string_questiontype') {
                   4623:                         $name = 'type';
1.588     raeburn  4624:                     } elsif (($typeof eq 'string_lenient') || ($typeof eq 'string_deeplink')) {
                   4625:                         ($name) = ($typeof =~ /^string_(lenient|deeplink)$/);
1.563     damieng  4626:                         my $stringmatch = &standard_string_matches($typeof);
                   4627:                         if (ref($stringmatch) eq 'ARRAY') {
                   4628:                             foreach my $item (@{$stringmatch}) {
                   4629:                                 if (ref($item) eq 'ARRAY') {
                   4630:                                     my ($regexpname,$pattern) = @{$item};
                   4631:                                     if ($pattern ne '') {
                   4632:                                         if ($data =~ /$pattern/) {
                   4633:                                             $valmatch = $regexpname;
                   4634:                                             $valchk = '';
                   4635:                                             last;
                   4636:                                         }
1.560     damieng  4637:                                     }
1.549     raeburn  4638:                                 }
                   4639:                             }
                   4640:                         }
1.563     damieng  4641:                     } elsif ($typeof eq 'string_discussvote') {
                   4642:                         $name = 'discussvote';
                   4643:                     } elsif ($typeof eq 'string_examcode') {
                   4644:                         $name = 'examcode';
                   4645:                         if (&Apache::lonnet::validCODE($data)) {
                   4646:                             $valchk = 'valid';
                   4647:                         }
                   4648:                     } elsif ($typeof eq 'string_yesno') {
                   4649:                         if ($thiskey =~ /\.retrypartial$/) {
                   4650:                             $name = 'retrypartial';
                   4651:                         }
1.621     raeburn  4652:                     } elsif ($typeof eq 'string_tex') {
                   4653:                         $name = 'texdisplay';
1.549     raeburn  4654:                     }
1.563     damieng  4655:                 } elsif ($cmd eq 'datepointer') {
                   4656:                     $data=&Apache::lonhtmlcommon::get_date_from_form($env{$key});
                   4657:                     $typeof=$env{'form.typeof_'.$thiskey};
                   4658:                     $text = &mt('Saved modified date for');
                   4659:                     if ($typeof eq 'date_start') {
                   4660:                         if ($thiskey =~ /\.printstartdate$/) {
                   4661:                             $name = 'printstartdate';
                   4662:                             if (($data) && ($data > $now)) {
                   4663:                                 $valchk = 'future';
                   4664:                             }
1.560     damieng  4665:                         }
1.563     damieng  4666:                     } elsif ($typeof eq 'date_end') {
                   4667:                         if ($thiskey =~ /\.printenddate$/) {
                   4668:                             $name = 'printenddate';
                   4669:                             if (($data) && ($data < $now)) {
                   4670:                                 $valchk = 'past';
                   4671:                             }
1.560     damieng  4672:                         }
1.504     raeburn  4673:                     }
1.563     damieng  4674:                 } elsif ($cmd eq 'dateinterval') {
                   4675:                     $data=&get_date_interval_from_form($thiskey);
                   4676:                     if ($thiskey =~ /\.interval$/) {
                   4677:                         $name = 'interval';
                   4678:                         my $intervaltype = &get_intervaltype($name);
                   4679:                         my $intervalmatch = &standard_interval_matches($intervaltype);
                   4680:                         if (ref($intervalmatch) eq 'ARRAY') {
                   4681:                             foreach my $item (@{$intervalmatch}) {
                   4682:                                 if (ref($item) eq 'ARRAY') {
                   4683:                                     my ($regexpname,$pattern) = @{$item};
                   4684:                                     if ($pattern ne '') {
                   4685:                                         if ($data =~ /$pattern/) {
                   4686:                                             $valmatch = $regexpname;
                   4687:                                             $valchk = '';
                   4688:                                             last;
                   4689:                                         }
1.560     damieng  4690:                                     }
1.554     raeburn  4691:                                 }
                   4692:                             }
                   4693:                         }
                   4694:                     }
1.563     damieng  4695:                     $typeof=$env{'form.typeof_'.$thiskey};
                   4696:                     $text = &mt('Saved modified date for');
1.554     raeburn  4697:                 }
1.576     raeburn  4698:                 if ($recursive) {
1.563     damieng  4699:                     $namematch = 'maplevelrecurse';
1.560     damieng  4700:                 }
1.563     damieng  4701:                 if (($name ne '') || ($namematch ne '')) {
                   4702:                     my ($needsrelease,$needsnewer);
                   4703:                     if ($name ne '') {
                   4704:                         $needsrelease = $Apache::lonnet::needsrelease{"parameter:$name:$valchk:$valmatch:"};
1.560     damieng  4705:                         if ($needsrelease) {
                   4706:                             unless ($got_chostname) {
1.563     damieng  4707:                                 ($chostname,$cmajor,$cminor)=&parameter_release_vars();
1.560     damieng  4708:                                 $got_chostname = 1;
                   4709:                             }
1.563     damieng  4710:                             $needsnewer = &parameter_releasecheck($name,$valchk,$valmatch,undef,
                   4711:                                                                 $needsrelease,
                   4712:                                                                 $cmajor,$cminor);
                   4713:                         }
                   4714:                     }
                   4715:                     if ($namematch ne '') {
                   4716:                         if ($needsnewer) {
                   4717:                             undef($namematch);
1.560     damieng  4718:                         } else {
1.563     damieng  4719:                             my $currneeded;
                   4720:                             if ($needsrelease) {
                   4721:                                 $currneeded = $needsrelease;
                   4722:                             }
                   4723:                             $needsrelease =
                   4724:                                 $Apache::lonnet::needsrelease{"parameter::::$namematch"};
                   4725:                             if (($needsrelease) &&
                   4726:                                     (($currneeded eq '') || ($needsrelease < $currneeded))) {
                   4727:                                 unless ($got_chostname) {
                   4728:                                     ($chostname,$cmajor,$cminor) = &parameter_release_vars();
                   4729:                                     $got_chostname = 1;
                   4730:                                 }
                   4731:                                 $needsnewer = &parameter_releasecheck(undef,$valchk,$valmatch,
                   4732:                                     $namematch, $needsrelease,$cmajor,$cminor);
                   4733:                             } else {
                   4734:                                 undef($namematch);
                   4735:                             }
1.560     damieng  4736:                         }
1.557     raeburn  4737:                     }
1.563     damieng  4738:                     if ($needsnewer) {
                   4739:                         $r->print('<br />'.&oldversion_warning($name,$namematch,$data,
                   4740:                                                             $chostname,$cmajor,
                   4741:                                                             $cminor,$needsrelease));
                   4742:                         next;
                   4743:                     }
1.504     raeburn  4744:                 }
1.576     raeburn  4745:                 my ($reconlychg,$haschange,$storekey);
                   4746:                 if ($tuname) {
                   4747:                     my $ustorekey;
                   4748:                     if ($altkey) {
                   4749:                         if ($recursive) {
                   4750:                             if (exists($$olddata{$thiskey})) {
                   4751:                                 if ($$olddata{$thiskey} eq $data) {
                   4752:                                     $reconlychg = 1;
                   4753:                                 }
                   4754:                                 &Apache::lonnet::del('resourcedata',[$tkeynonrec,$tkeynonrec.'.type'],$tudom,$tuname);
                   4755:                             }
                   4756:                             if (exists($$olddata{$altkey})) {
                   4757:                                 if (defined($data) && $$olddata{$altkey} ne $data) {
                   4758:                                     $haschange = 1;
                   4759:                                 }
                   4760:                             } elsif ((!$reconlychg) && ($data ne '')) {
                   4761:                                 $haschange = 1;
                   4762:                             }
                   4763:                             $ustorekey = $tkeyrec;
                   4764:                         } else {
                   4765:                             if (exists($$olddata{$altkey})) {
                   4766:                                 if ($$olddata{$altkey} eq $data) {
                   4767:                                     $reconlychg = 1;
                   4768:                                 }
                   4769:                                 &Apache::lonnet::del('resourcedata',[$tkeyrec,$tkeyrec.'.type'],$tudom,$tuname);
                   4770:                             }
                   4771:                             if (exists($$olddata{$thiskey})) {
                   4772:                                 if (defined($data) && $$olddata{$thiskey} ne $data) {
                   4773:                                     $haschange = 1;
                   4774:                                 }
                   4775:                             } elsif ((!$reconlychg) && ($data ne '')) {
                   4776:                                 $haschange = 1;
                   4777:                             }
                   4778:                             $ustorekey = $tkeynonrec;
                   4779:                         }
                   4780:                     } else {
                   4781:                         if (exists($$olddata{$tkey})) {
                   4782:                             if (defined($data) && $$olddata{$tkey} ne $data) {
                   4783:                                 $haschange = 1;
                   4784:                             }
                   4785:                             $ustorekey = $tkey;
                   4786:                         }
                   4787:                     }
                   4788:                     if ($haschange || $reconlychg)  {
                   4789:                         unless ($env{'form.del_'.$thiskey}) {
                   4790:                             if (&Apache::lonnet::put('resourcedata',{$ustorekey=>$data,
                   4791:                                                                      $ustorekey.'.type' => $typeof},
                   4792:                                                                      $tudom,$tuname) eq 'ok') {
                   4793:                                 &log_parmset({$ustorekey=>$data,$ustorekey.'.type' => $typeof},0,$tuname,$tudom);
                   4794:                                 $r->print('<br />'.$text.' '.
                   4795:                                           &Apache::loncommon::plainname($tuname,$tudom));
                   4796:                             } else {
                   4797:                                 $r->print('<div class="LC_error">'.
                   4798:                                           &mt('Error saving parameters').'</div>');
                   4799:                             }
                   4800:                             &Apache::lonnet::devalidateuserresdata($tuname,$tudom);
                   4801:                         }
                   4802:                     }
                   4803:                 } else {
                   4804:                     if ($altkey) {
                   4805:                         if ($recursive) {
                   4806:                             if (exists($$olddata{$thiskey})) {
                   4807:                                 if ($$olddata{$thiskey} eq $data) {
                   4808:                                     $reconlychg = 1;
                   4809:                                 }
                   4810:                                 push(@delnonrec,($thiskey,$thiskey.'.type'));
                   4811:                             }
                   4812:                             if (exists($$olddata{$altkey})) {
                   4813:                                 if (defined($data) && $$olddata{$altkey} ne $data) {
                   4814:                                     $haschange = 1;
                   4815:                                 }
                   4816:                             } elsif (($data ne '') && (!$reconlychg)) {
                   4817:                                 $haschange = 1;
                   4818:                             }
                   4819:                             $storekey = $altkey;
1.563     damieng  4820:                         } else {
1.576     raeburn  4821:                             if (exists($$olddata{$altkey})) {
                   4822:                                 if ($$olddata{$altkey} eq $data) {
                   4823:                                     $reconlychg = 1;
                   4824:                                 }
                   4825:                                 push(@delrec,($altkey,$altkey.'.type'));
                   4826:                             } 
                   4827:                             if (exists($$olddata{$thiskey})) {
                   4828:                                 if (defined($data) && $$olddata{$thiskey} ne $data) {
                   4829:                                     $haschange = 1;
                   4830:                                 }
                   4831:                             } elsif (($data ne '') && (!$reconlychg)) {
                   4832:                                 $haschange = 1;
                   4833:                             }
                   4834:                             $storekey = $thiskey;
1.563     damieng  4835:                         }
1.560     damieng  4836:                     } else {
1.576     raeburn  4837:                         if (defined($data) && $$olddata{$thiskey} ne $data) {
                   4838:                             $haschange = 1;
                   4839:                             $storekey = $thiskey;
                   4840:                         }
                   4841:                     }
                   4842:                 }
                   4843:                 if ($reconlychg || $haschange) {
                   4844:                     unless ($env{'form.del_'.$thiskey}) {
                   4845:                         $newdata{$storekey}=$data;
                   4846:                         $newdata{$storekey.'.type'}=$typeof;
1.560     damieng  4847:                     }
                   4848:                 }
                   4849:             } elsif ($cmd eq 'del') {
                   4850:                 if ($tuname) {
1.576     raeburn  4851:                     my $error;
                   4852:                     if ($altkey) {  
                   4853:                         if (exists($$olddata{$altkey})) {
                   4854:                             if (&Apache::lonnet::del('resourcedata',[$tkeyrec,$tkeyrec.'.type'],$tudom,$tuname) eq 'ok') {
                   4855:                                 &log_parmset({$tkeyrec=>''},1,$tuname,$tudom);
                   4856:                                 if ($recursive) {
                   4857:                                     $r->print('<br />'.&mt('Deleted parameter for').' '.&Apache::loncommon::plainname($tuname,$tudom));
                   4858:                                 }
                   4859:                             } elsif ($recursive) {
                   4860:                                 $error = 1;
                   4861:                             }
                   4862:                         }
                   4863:                         if (exists($$olddata{$thiskey})) {
                   4864:                             if (&Apache::lonnet::del('resourcedata',[$tkeynonrec,$tkeynonrec.'.type'],$tudom,$tuname) eq 'ok') {
                   4865:                                 &log_parmset({$tkeynonrec=>''},1,$tuname,$tudom);
                   4866:                                 unless ($recursive) {
                   4867:                                     $r->print('<br />'.&mt('Deleted parameter for').' '.&Apache::loncommon::plainname($tuname,$tudom));
                   4868:                                 }
                   4869:                             } elsif (!$recursive) {
                   4870:                                 $error = 1;
                   4871:                             }
                   4872:                         }
1.560     damieng  4873:                     } else {
1.576     raeburn  4874:                         if (exists($$olddata{$thiskey})) {
                   4875:                             if (&Apache::lonnet::del('resourcedata',[$tkey,$tkey.'.type'],$tudom,$tuname) eq 'ok') {
                   4876:                                 &log_parmset({$tkey=>''},1,$tuname,$tudom);
                   4877:                                 $r->print('<br />'.&mt('Deleted parameter for').' '.&Apache::loncommon::plainname($tuname,$tudom));
                   4878:                             } else {
                   4879:                                 $error = 1;
                   4880:                             }
                   4881:                         }
                   4882:                     }
                   4883:                     if ($error) { 
1.560     damieng  4884:                         $r->print('<div class="LC_error">'.
                   4885:                             &mt('Error deleting parameters').'</div>');
                   4886:                     }
                   4887:                     &Apache::lonnet::devalidateuserresdata($tuname,$tudom);
                   4888:                 } else {
1.576     raeburn  4889:                     if ($altkey) {
                   4890:                         if (exists($$olddata{$altkey})) {
                   4891:                             unless (grep(/^\Q$altkey\E$/,@delrec)) {
                   4892:                                 push(@deldata,($altkey,$altkey.'.type'));
                   4893:                             }
                   4894:                         }
                   4895:                         if (exists($$olddata{$thiskey})) {
                   4896:                             unless (grep(/^\Q$thiskey\E$/,@delnonrec)) {
                   4897:                                 push(@deldata,($thiskey,$thiskey.'.type'));
                   4898:                             }
                   4899:                         }
                   4900:                     } elsif (exists($$olddata{$thiskey})) {
                   4901:                         push(@deldata,($thiskey,$thiskey.'.type'));
                   4902:                     }
1.560     damieng  4903:                 }
1.473     amueller 4904:             }
                   4905:         }
                   4906:     }
1.207     www      4907: # Store all course level
1.144     www      4908:     my $delentries=$#deldata+1;
1.576     raeburn  4909:     my @alldels;
                   4910:     if (@delrec) {
                   4911:         push(@alldels,@delrec);
                   4912:     }
                   4913:     if (@delnonrec) {
                   4914:         push(@alldels,@delnonrec);
                   4915:     }
                   4916:     if (@deldata) {
                   4917:         push(@alldels,@deldata);
                   4918:     }
1.548     raeburn  4919:     my @newdatakeys=keys(%newdata);
1.144     www      4920:     my $putentries=$#newdatakeys+1;
1.576     raeburn  4921:     my ($delresult,$devalidate);
                   4922:     if (@alldels) {
                   4923:         if (&Apache::lonnet::del('resourcedata',\@alldels,$dom,$crs) eq 'ok') {
                   4924:             my %loghash=map { $_ => '' } @alldels;
1.560     damieng  4925:             &log_parmset(\%loghash,1);
1.576     raeburn  4926:             if ($delentries) {
                   4927:                 $r->print('<h2>'.&mt('Deleted [quant,_1,parameter]',$delentries/2).'</h2>');
                   4928:             }
                   4929:         } elsif ($delentries) {
1.560     damieng  4930:             $r->print('<div class="LC_error">'.
                   4931:                 &mt('Error deleting parameters').'</div>');
                   4932:         }
1.576     raeburn  4933:         $devalidate = 1; 
1.144     www      4934:     }
                   4935:     if ($putentries) {
1.560     damieng  4936:         if (&Apache::lonnet::put('resourcedata',\%newdata,$dom,$crs) eq 'ok') {
                   4937:                     &log_parmset(\%newdata,0);
                   4938:             $r->print('<h3>'.&mt('Saved [quant,_1,parameter]',$putentries/2).'</h3>');
                   4939:         } else {
                   4940:             $r->print('<div class="LC_error">'.
                   4941:                 &mt('Error saving parameters').'</div>');
                   4942:         }
1.576     raeburn  4943:         $devalidate = 1; 
                   4944:     }
                   4945:     if ($devalidate) {
1.560     damieng  4946:         &Apache::lonnet::devalidatecourseresdata($crs,$dom);
1.144     www      4947:     }
1.208     www      4948: }
1.207     www      4949: 
1.563     damieng  4950: # Returns the username and domain from a key created in readdata from a resourcedata key.
                   4951: #
                   4952: # @param {string} $key - the key
                   4953: # @returns {Array}
1.208     www      4954: sub extractuser {
                   4955:     my $key=shift;
1.350     albertel 4956:     return ($key=~/^$env{'request.course.id'}.\[useropt\:($match_username)\:($match_domain)\]\./);
1.208     www      4957: }
1.206     www      4958: 
1.563     damieng  4959: # Parses a parameter key and returns the components.
                   4960: #
                   4961: # @param {string} $key - 
                   4962: # @param {hash reference} $listdata - 
                   4963: # @return {Array} - (student, resource, part, parameter)
1.381     albertel 4964: sub parse_listdata_key {
                   4965:     my ($key,$listdata) = @_;
                   4966:     # split into student/section affected, and
                   4967:     # the realm (folder/resource part and parameter
1.446     bisitz   4968:     my ($student,$realm) =
1.473     amueller 4969:     ($key=~/^\Q$env{'request.course.id'}\E\.\[([^\.]+)\]\.(.+)$/);
1.381     albertel 4970:     # if course wide student would be undefined
                   4971:     if (!defined($student)) {
1.560     damieng  4972:         ($realm)=($key=~/^\Q$env{'request.course.id'}\E\.(.+)$/);
1.381     albertel 4973:     }
                   4974:     # strip off the .type if it's not the Question type parameter
                   4975:     if ($realm=~/\.type$/ && !exists($listdata->{$key.'.type'})) {
1.560     damieng  4976:         $realm=~s/\.type//;
1.381     albertel 4977:     }
                   4978:     # split into resource+part and parameter name
1.388     albertel 4979:     my ($res,    $parm) = ($realm=~/^(.*)\.(.*)$/);
                   4980:        ($res, my $part) = ($res  =~/^(.*)\.(.*)$/);
1.381     albertel 4981:     return ($student,$res,$part,$parm);
                   4982: }
                   4983: 
1.563     damieng  4984: # Prints HTML with forms for the given parameter data in overview mode (newoverview or overview).
                   4985: #
                   4986: # @param {Apache2::RequestRec} $r - the Apache request
                   4987: # @param {hash reference} $resourcedata - parameter data returned by readdata
                   4988: # @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
                   4989: # @param {string} $sortorder - realmstudent|studentrealm
                   4990: # @param {string} $caller - name of the calling sub (overview|newoverview)
                   4991: # @param {hash reference} $classlist - from loncoursedata::get_classlist
1.568     raeburn  4992: # @param {boolean} $readonly - true if editing not allowed
1.608     raeburn  4993: # @param {string} $parmlev - full|map
                   4994: # @param {hash reference} $hash_for_realm - keys: realm, values: numeric order  
                   4995: # @param {string} $pschp - selected map pc, or 'all'
1.563     damieng  4996: # @returns{integer} - number of $listdata parameters processed
1.208     www      4997: sub listdata {
1.608     raeburn  4998:     my ($r,$resourcedata,$listdata,$sortorder,$caller,$classlist,$readonly,$parmlev,$hash_for_realm,$pschp)=@_;
1.552     raeburn  4999:     
1.207     www      5000: # Start list output
1.206     www      5001: 
1.122     www      5002:     my $oldsection='';
                   5003:     my $oldrealm='';
                   5004:     my $oldpart='';
1.123     www      5005:     my $pointer=0;
1.124     www      5006:     $tableopen=0;
1.145     www      5007:     my $foundkeys=0;
1.248     albertel 5008:     my %keyorder=&standardkeyorder();
1.594     raeburn  5009:     my $readonlyall = $readonly;
1.381     albertel 5010: 
1.552     raeburn  5011:     my ($secidx,%grouphash);
                   5012:     if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5013:         $secidx = &Apache::loncoursedata::CL_SECTION();
1.553     raeburn  5014:         if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   5015:             %grouphash = &Apache::longroup::coursegroups();
                   5016:         } elsif ($env{'request.course.groups'} ne '') {
1.585     raeburn  5017:             map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'});
1.553     raeburn  5018:         }
1.552     raeburn  5019:     }
                   5020: 
1.576     raeburn  5021:     foreach my $key (sort {
1.560     damieng  5022:         my ($astudent,$ares,$apart,$aparm) = &parse_listdata_key($a,$listdata);
                   5023:         my ($bstudent,$bres,$bpart,$bparm) = &parse_listdata_key($b,$listdata);
1.608     raeburn  5024:         my ($aid,$bid);
                   5025:         if ($caller eq 'newoverview') {
                   5026:             if (ref($hash_for_realm) eq 'HASH') {
                   5027:                 if (($parmlev eq 'map') && ($pschp eq 'all')) {
                   5028:                     my ($aurl) = ($ares =~ /^(.+\.(?:sequence|page))___\(all\)$/);
                   5029:                     my ($burl) = ($bres =~ /^(.+\.(?:sequence|page))___\(all\)$/);
                   5030:                     $aid = $hash_for_realm->{$aurl};
                   5031:                     $bid = $hash_for_realm->{$burl};
                   5032:                 } elsif ($parmlev eq 'full') {
                   5033:                     $aid = $hash_for_realm->{$ares};
                   5034:                     $bid = $hash_for_realm->{$bres};
                   5035:                 }
                   5036:             }
                   5037:         }
1.381     albertel 5038: 
1.560     damieng  5039:         # get the numerical order for the param
                   5040:         $aparm=$keyorder{'parameter_0_'.$aparm};
                   5041:         $bparm=$keyorder{'parameter_0_'.$bparm};
1.381     albertel 5042: 
1.560     damieng  5043:         my $result=0;
1.381     albertel 5044: 
1.560     damieng  5045:         if ($sortorder eq 'realmstudent') {
1.381     albertel 5046:             if ($ares     ne $bres    ) {
1.608     raeburn  5047:                 if ($caller eq 'newoverview') {
                   5048:                     if (ref($hash_for_realm) eq 'HASH') {
                   5049:                         if (($parmlev eq 'map') && ($pschp eq 'all')) {
                   5050:                             $result = ($aid <=> $bid);
                   5051:                         } elsif ($parmlev eq 'full') {
                   5052:                             $result = ($aid <=> $bid);
                   5053:                         } else {
                   5054:                             $result = ($ares cmp $bres);
                   5055:                         }
                   5056:                     } else {
                   5057:                         $result = ($ares cmp $bres);
                   5058:                     }
                   5059:                 } else {
                   5060:                     $result = ($ares cmp $bres);
                   5061:                 }
1.446     bisitz   5062:             } elsif ($astudent ne $bstudent) {
1.560     damieng  5063:                 $result = ($astudent cmp $bstudent);
                   5064:             } elsif ($apart    ne $bpart   ) {
                   5065:                 $result = ($apart    cmp $bpart);
                   5066:             }
                   5067:         } else {
                   5068:             if      ($astudent ne $bstudent) {
                   5069:                 $result = ($astudent cmp $bstudent);
                   5070:             } elsif ($ares     ne $bres    ) {
1.608     raeburn  5071:                 if ($caller eq 'newoverview') {
                   5072:                     if (ref($hash_for_realm) eq 'HASH') {
                   5073:                         if (($parmlev eq 'map') && ($pschp eq 'all')) {
                   5074:                             $result = ($aid <=> $bid);
                   5075:                         } elsif ($parmlev eq 'full') {
                   5076:                             $result = ($aid <=> $bid);
                   5077:                         } else {
                   5078:                             $result = ($ares cmp $bres);
                   5079:                         }
                   5080:                     } else {
                   5081:                         $result = ($ares cmp $bres);
                   5082:                     }
                   5083:                 } else {
                   5084:                     $result = ($ares cmp $bres);
                   5085:                 }
1.560     damieng  5086:             } elsif ($apart    ne $bpart   ) {
                   5087:                 $result = ($apart    cmp $bpart);
                   5088:             }
1.473     amueller 5089:         }
1.446     bisitz   5090: 
1.560     damieng  5091:         if (!$result) {
1.381     albertel 5092:             if (defined($aparm) && defined($bparm)) {
1.560     damieng  5093:                 $result = ($aparm <=> $bparm);
1.381     albertel 5094:             } elsif (defined($aparm)) {
1.560     damieng  5095:                 $result = -1;
1.381     albertel 5096:             } elsif (defined($bparm)) {
1.560     damieng  5097:                 $result = 1;
                   5098:             }
1.473     amueller 5099:         }
1.381     albertel 5100: 
1.560     damieng  5101:         $result;
                   5102:         
1.576     raeburn  5103:     } keys(%{$listdata})) { # foreach my $key
                   5104:         my $thiskey = $key;
1.560     damieng  5105:         if ($$listdata{$thiskey.'.type'}) {
                   5106:             my $thistype=$$listdata{$thiskey.'.type'};
                   5107:             if ($$resourcedata{$thiskey.'.type'}) {
                   5108:                 $thistype=$$resourcedata{$thiskey.'.type'};
                   5109:             }
                   5110:             my ($middle,$part,$name)=
1.572     damieng  5111:                 ($thiskey=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.560     damieng  5112:             my $section=&mt('All Students');
1.594     raeburn  5113:             $readonly = $readonlyall;
1.599     raeburn  5114:             my $userscope;
1.576     raeburn  5115:             my $showval = $$resourcedata{$thiskey}; 
1.560     damieng  5116:             if ($middle=~/^\[(.*)\]/) {
                   5117:                 my $issection=$1;
                   5118:                 if ($issection=~/^useropt\:($match_username)\:($match_domain)/) {
                   5119:                     my ($stuname,$studom) = ($1,$2);
                   5120:                     if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5121:                         if (ref($classlist) eq 'HASH') {
                   5122:                             if (ref($classlist->{$stuname.':'.$studom}) eq 'ARRAY') {
                   5123:                                 next unless ($classlist->{$stuname.':'.$studom}->[$secidx] eq $env{'request.course.sec'}); 
                   5124:                             }
                   5125:                         }
                   5126:                     }
                   5127:                     $section=&mt('User').": ".&Apache::loncommon::plainname($stuname,$studom);
1.599     raeburn  5128:                     $userscope = 1;
1.560     damieng  5129:                 } else {
                   5130:                     if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5131:                         if (exists($grouphash{$issection})) {
                   5132:                             $section=&mt('Group').': '.$issection;
                   5133:                         } elsif ($issection eq $env{'request.course.sec'}) {
                   5134:                             $section = &mt('Section').': '.$issection;
                   5135:                         } else {
                   5136:                             next; 
1.552     raeburn  5137:                         }
1.560     damieng  5138:                     } else {
                   5139:                         $section=&mt('Group/Section').': '.$issection;
1.552     raeburn  5140:                     }
                   5141:                 }
1.560     damieng  5142:                 $middle=~s/^\[(.*)\]//;
                   5143:             } elsif (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5144:                 $readonly = 1;
                   5145:             }
                   5146:             $middle=~s/\.+$//;
                   5147:             $middle=~s/^\.+//;
                   5148:             my $realm='<span class="LC_parm_scope_all">'.&mt('All Resources').'</span>';
1.576     raeburn  5149:             my ($is_map,$is_recursive,$mapurl,$maplevel);
                   5150:             if ($caller eq 'overview') {
                   5151:                 if ($middle=~/^(.+)\_\_\_\((all|rec)\)$/) {
                   5152:                     $mapurl = $1;
                   5153:                     $maplevel = $2;
                   5154:                     $is_map = 1;
                   5155:                 }
                   5156:             } elsif ($caller eq 'newoverview') {
                   5157:                 if ($middle=~/^(.+)\_\_\_\((all)\)$/) {
                   5158:                     $mapurl = $1;
                   5159:                     $maplevel = $2;
                   5160:                     $is_map = 1;
                   5161:                 }
                   5162:             }
                   5163:             if ($is_map) {
1.560     damieng  5164:                 my $leveltitle = &mt('Folder/Map');
1.615     raeburn  5165:                 my $title = &Apache::lonnet::gettitle($mapurl);
1.608     raeburn  5166:                 if (ref($hash_for_realm) eq 'HASH') {
                   5167:                     if ($hash_for_realm->{$mapurl} eq '1') {
                   5168:                         $title = &mt('Main Content');
                   5169:                     }
                   5170:                 }
1.576     raeburn  5171:                 unless (($name eq 'hiddenresource') || ($name eq 'encrypturl')) {   
                   5172:                     if ($caller eq 'newoverview') {
                   5173:                         my $altkey = $thiskey;
                   5174:                         $altkey =~ s/\Q___(all)\E/___(rec)/;
                   5175:                         if ((exists($$resourcedata{$altkey})) & (!exists($$resourcedata{$thiskey}))) {
                   5176:                             $is_recursive = 1;
                   5177:                             if ($$resourcedata{$altkey.'.type'}) {
                   5178:                                 $thistype=$$resourcedata{$altkey.'.type'};
                   5179:                             }
                   5180:                             $showval = $$resourcedata{$altkey};
                   5181:                         }
                   5182:                     } elsif (($caller eq 'overview') && ($maplevel eq 'rec')) {
                   5183:                         $thiskey =~ s/\Q___(rec)\E/___(all)/;
                   5184:                         $is_recursive = 1;
                   5185:                     }
1.560     damieng  5186:                 }
1.608     raeburn  5187:                 $realm='<span class="LC_parm_scope_folder">'.$leveltitle.': '.$title.' <br /><span class="LC_parm_folder">('.$mapurl.')</span></span>';
1.560     damieng  5188:             } elsif ($middle) {
                   5189:                 my ($map,$id,$url)=&Apache::lonnet::decode_symb($middle);
1.609     raeburn  5190:                 next if (($url =~ /\.(page|sequence)$/) && ($parmlev eq 'full') && ($caller eq 'newoverview'));
1.560     damieng  5191:                 $realm='<span class="LC_parm_scope_resource">'.&mt('Resource').
                   5192:                     ': '.&Apache::lonnet::gettitle($middle).
                   5193:                     ' <br /><span class="LC_parm_symb">('.$url.' in '.$map.' id: '.
                   5194:                     $id.')</span></span>';
                   5195:             }
                   5196:             if ($sortorder eq 'realmstudent') {
                   5197:                 if ($realm ne $oldrealm) {
                   5198:                     $r->print(&tableend()."\n<hr /><h1>$realm</h1>");
                   5199:                     $oldrealm=$realm;
                   5200:                     $oldsection='';
                   5201:                 }
                   5202:                 if ($section ne $oldsection) {
                   5203:                     $r->print(&tableend()."\n<h2>$section</h2>");
                   5204:                     $oldsection=$section;
                   5205:                     $oldpart='';
                   5206:                 }
1.552     raeburn  5207:             } else {
1.560     damieng  5208:                 if ($section ne $oldsection) {
                   5209:                     $r->print(&tableend()."\n<hr /><h1>$section</h1>");
                   5210:                     $oldsection=$section;
                   5211:                     $oldrealm='';
                   5212:                 }
                   5213:                 if ($realm ne $oldrealm) {
                   5214:                     $r->print(&tableend()."\n<h2>$realm</h2>");
                   5215:                     $oldrealm=$realm;
                   5216:                     $oldpart='';
1.552     raeburn  5217:                 }
                   5218:             }
1.560     damieng  5219:             if ($part ne $oldpart) {
                   5220:                 $r->print(&tableend().
                   5221:                     "\n".'<span class="LC_parm_part">'.&mt('Part').": $part</span>");
                   5222:                 $oldpart=$part;
1.556     raeburn  5223:             }
1.560     damieng  5224:     #
                   5225:     # Ready to print
                   5226:     #
1.470     raeburn  5227:             my $parmitem = &standard_parameter_names($name);
1.619     raeburn  5228:             my $advice;
                   5229:             if (($name eq 'mapalias') && ($middle) && (!$is_map)) {
                   5230:                 if ($middle =~ m{^uploaded/}) {
                   5231:                     $advice = &mt('Use Course Editor to set this.');
                   5232:                 } else {
                   5233:                     $advice = &mt('Use Resource Assembly Tool to set this.');
                   5234:                 }
                   5235:                 $advice = '<br /><span class="LC_fontsize_small LC_cusr_emph">'.$advice.'</span>';
                   5236:             }
1.576     raeburn  5237:             $r->print(&tablestart($readonly,$is_map).
1.560     damieng  5238:                 &Apache::loncommon::start_data_table_row().
                   5239:                 '<td><b>'.&mt($parmitem).
1.619     raeburn  5240:                 '</b>'.$advice.'</td>');
1.560     damieng  5241:             unless ($readonly) {
1.599     raeburn  5242:                 my $disabled;
                   5243:                 if (($name eq 'availablestudent') &&
                   5244:                     (($showval eq '') || ($userscope))) {
                   5245:                     $disabled = ' disabled="disabled"';
1.619     raeburn  5246:                 } elsif (($name eq 'mapalias') && ($showval eq '')) {
                   5247:                     $disabled = ' disabled="disabled"';
1.599     raeburn  5248:                 }
1.560     damieng  5249:                 $r->print('<td><input type="checkbox" name="del_'.
1.599     raeburn  5250:                         $thiskey.'"'.$disabled.' /></td>');
1.560     damieng  5251:             }
                   5252:             $r->print('<td>');
                   5253:             $foundkeys++;
                   5254:             if (&isdateparm($thistype)) {
                   5255:                 my $jskey='key_'.$pointer;
                   5256:                 my $state;
                   5257:                 $pointer++;
                   5258:                 if ($readonly) {
                   5259:                     $state = 'disabled';
                   5260:                 }
                   5261:                 $r->print(
                   5262:                     &Apache::lonhtmlcommon::date_setter('parmform',
                   5263:                                                         $jskey,
1.576     raeburn  5264:                                                         $showval,
1.560     damieng  5265:                                                         '',1,$state));
                   5266:                 unless  ($readonly) {
                   5267:                     $r->print(
                   5268:     '<input type="hidden" name="datepointer_'.$thiskey.'" value="'.$jskey.'" />'.
1.576     raeburn  5269:     (($showval!=0)?'<span class="LC_nobreak"><a href="/adm/parmset?&action=dateshift1&timebase='.$showval.'">'.
1.560     damieng  5270:     &mt('Shift all dates based on this date').'</a></span>':'').
1.576     raeburn  5271:     &date_sanity_info($showval)
1.560     damieng  5272:                     );
                   5273:                 }
                   5274:             } elsif ($thistype eq 'date_interval') {
                   5275:                 $r->print(&date_interval_selector($thiskey,$name,
1.576     raeburn  5276:                           $showval,$readonly));
1.560     damieng  5277:             } elsif ($thistype =~ m/^string/) {
1.599     raeburn  5278:                 if ($name eq 'availablestudent') {
                   5279:                     $readonly = 1;
1.619     raeburn  5280:                 } elsif (($name eq 'mapalias') && ($showval eq '')) {
                   5281:                     $readonly = 1;
1.599     raeburn  5282:                 }
1.560     damieng  5283:                 $r->print(&string_selector($thistype,$thiskey,
1.576     raeburn  5284:                           $showval,$name,$readonly));
1.560     damieng  5285:             } else {
1.576     raeburn  5286:                 $r->print(&default_selector($thiskey,$showval,$readonly));
1.552     raeburn  5287:             }
1.560     damieng  5288:             unless ($readonly) {
                   5289:                 $r->print('<input type="hidden" name="typeof_'.$thiskey.'" value="'.
                   5290:                         $thistype.'" />');
1.552     raeburn  5291:             }
1.576     raeburn  5292:             $r->print('</td>');
                   5293:             if ($is_map) {
                   5294:                 if (($name eq 'encrypturl') || ($name eq 'hiddenresource')) {
                   5295:                     $r->print('<td><table><tr><td>'.&mt('Yes').'</td></tr></table></td>');
                   5296:                 } else {
                   5297:                     my ($disabled,$recon,$recoff);
                   5298:                     if ($readonly) {
                   5299:                         $disabled = ' disabled="disabled"';
                   5300:                     }
                   5301:                     if ($is_recursive) {
                   5302:                         $recon = ' checked="checked"';
                   5303:                     } else {
                   5304:                         $recoff = ' checked="checked"';
                   5305:                     }
                   5306:                     $r->print('<td><table><tr><td><label><input type="radio" name="rec_'.$thiskey.'" value="1"'.$recon.$disabled.' />'.&mt('Yes').'</label>'.
                   5307:                               '</td><td><label><input type="radio" name="rec_'.$thiskey.'" value="0"'.$recoff.$disabled.' />'.&mt('No').'</label></td></tr></table></td>');
                   5308:                 }
                   5309:             }
                   5310:             $r->print(&Apache::loncommon::end_data_table_row());
1.473     amueller 5311:         }
1.121     www      5312:     }
1.208     www      5313:     return $foundkeys;
                   5314: }
                   5315: 
1.563     damieng  5316: # Returns a string representing the interval, directly using form data matching the given key.
                   5317: # The returned string may also include information related to proctored exams.
                   5318: # Format: seconds['_done'[':'done button title':']['_proctor'['_'proctor key]]]
                   5319: #
                   5320: # @param {string} $key - suffix for form fields related to the interval
                   5321: # @returns {string}
1.385     albertel 5322: sub get_date_interval_from_form {
                   5323:     my ($key) = @_;
                   5324:     my $seconds = 0;
1.611     raeburn  5325:     my $numnotnull = 0;
1.385     albertel 5326:     foreach my $which (['days', 86400],
1.473     amueller 5327:                ['hours', 3600],
                   5328:                ['minutes', 60],
                   5329:                ['seconds',  1]) {
1.560     damieng  5330:         my ($name, $factor) = @{ $which };
                   5331:         if (defined($env{'form.'.$name.'_'.$key})) {
1.611     raeburn  5332:             unless ($env{'form.'.$name.'_'.$key} eq '') {
                   5333:                 $numnotnull ++;
                   5334:                 $seconds += $env{'form.'.$name.'_'.$key} * $factor;
                   5335:             }
1.560     damieng  5336:         }
1.473     amueller 5337:     }
1.560     damieng  5338:     if (($key =~ /\.interval$/) &&
                   5339:             (($env{'form.done_'.$key} eq '_done') || ($env{'form.done_'.$key} eq '_done_proctor'))) {
1.559     raeburn  5340:         if ($env{'form.done_'.$key.'_buttontext'}) {
                   5341:             $env{'form.done_'.$key.'_buttontext'} =~ s/\://g;
                   5342:             $seconds .= '_done:'.$env{'form.done_'.$key.'_buttontext'}.':';
                   5343:             if ($env{'form.done_'.$key} eq '_done_proctor') {
                   5344:                 $seconds .= '_proctor';
                   5345:             }
                   5346:         } else {
                   5347:             $seconds .= $env{'form.done_'.$key}; 
                   5348:         }
                   5349:         if (($env{'form.done_'.$key} eq '_done_proctor') && 
1.560     damieng  5350:                 ($env{'form.done_'.$key.'_proctorkey'})) {
1.558     raeburn  5351:             $seconds .= '_'.$env{'form.done_'.$key.'_proctorkey'};
                   5352:         }
1.554     raeburn  5353:     }
1.611     raeburn  5354:     return if (!$numnotnull);
1.385     albertel 5355:     return $seconds;
                   5356: }
                   5357: 
1.563     damieng  5358: # Returns HTML to enter a text value for a parameter.
                   5359: #
                   5360: # @param {string} $thiskey - parameter key
                   5361: # @param {string} $showval - the current value
                   5362: # @param {boolean} $readonly - true if the field should not be made editable
                   5363: # @returns {string}
1.383     albertel 5364: sub default_selector {
1.552     raeburn  5365:     my ($thiskey, $showval, $readonly) = @_;
                   5366:     my $disabled;
                   5367:     if ($readonly) {
                   5368:         $disabled = ' disabled="disabled"';
                   5369:     }
                   5370:     return '<input type="text" name="set_'.$thiskey.'" value="'.$showval.'"'.$disabled.' />';
1.383     albertel 5371: }
                   5372: 
1.563     damieng  5373: # Returns HTML to enter allow/deny rules related to IP addresses.
                   5374: #
                   5375: # @param {string} $thiskey - parameter key
                   5376: # @param {string} $showval - the current value
                   5377: # @param {boolean} $readonly - true if the fields should not be made editable
                   5378: # @returns {string}
1.549     raeburn  5379: sub string_ip_selector {
1.552     raeburn  5380:     my ($thiskey, $showval, $readonly) = @_;
1.549     raeburn  5381:     my %access = (
                   5382:                    allow => [],
                   5383:                    deny  => [],
                   5384:                  );
                   5385:     if ($showval ne '') {
                   5386:         my @current;
                   5387:         if ($showval =~ /,/) {
                   5388:             @current = split(/,/,$showval);
                   5389:         } else {
                   5390:             @current = ($showval);
                   5391:         }
                   5392:         foreach my $item (@current) {
                   5393:             if ($item =~ /^\!([\[\]a-zA-Z\.\d\*\-]+)$/) {
                   5394:                 push(@{$access{'deny'}},$1);
                   5395:             } elsif ($item =~ /^([\[\]a-zA-Z\.\d\*\-]+)$/) {
                   5396:                 push(@{$access{'allow'}},$item);
                   5397:             }
                   5398:         }
                   5399:     }
                   5400:     if (!@{$access{'allow'}}) {
                   5401:         @{$access{'allow'}} = ('');
                   5402:     }
                   5403:     if (!@{$access{'deny'}}) {
                   5404:         @{$access{'deny'}} = ('');
                   5405:     }
1.552     raeburn  5406:     my ($disabled,$addmore);
1.567     raeburn  5407:     if ($readonly) {
1.552     raeburn  5408:         $disabled=' disabled="disabled"';
                   5409:     } else {
                   5410:         $addmore = "\n".'<button class="LC_add_ipacc_button">'.&mt('Add more').'</button>';
                   5411:     }
1.549     raeburn  5412:     my $output = '<input type="hidden" name="set_'.$thiskey.'" />
                   5413: <table><tr><th>'.&mt('Allow from').'</th><th>'.&mt('Deny from').'</th></tr><tr>';
                   5414:     foreach my $acctype ('allow','deny') {
                   5415:         $output .= '
                   5416: <td valign="top">
                   5417: <div class="LC_string_ipacc_wrap" id="LC_string_ipacc_'.$acctype.'_'.$thiskey.'">
                   5418:   <div class="LC_string_ipacc_inner">'."\n";
                   5419:         my $num = 0;
                   5420:         foreach my $curr (@{$access{$acctype}}) {
1.552     raeburn  5421:             $output .= '<div><input type="text" name="setip'.$acctype.'_'.$thiskey.'" value="'.$curr.'"'.$disabled.' />';
1.549     raeburn  5422:             if ($num > 0) {
                   5423:                 $output .= '<a href="#" class="LC_remove_ipacc">'.&mt('Remove').'</a>'; 
                   5424:             }
                   5425:             $output .= '</div>'."\n";
                   5426:             $num ++;
                   5427:         }
                   5428:         $output .= '
1.552     raeburn  5429:   </div>'.$addmore.'
1.549     raeburn  5430: </div>
                   5431: </td>';
                   5432:    }
                   5433:    $output .= '
                   5434: </tr>
                   5435: </table>'."\n";
                   5436:     return $output;
                   5437: }
                   5438: 
1.588     raeburn  5439: sub string_deeplink_selector {
                   5440:     my ($thiskey, $showval, $readonly) = @_;
1.616     raeburn  5441:     my (@tables,%values,@current,%titles,%options,%optiontext,%defaults,
                   5442:         %selectnull,%domlti,%crslti,@possmenus,%components);
                   5443:     @tables = ('upper','lower');
                   5444:     %components = (
                   5445:                     upper => ['state','others','listing','scope'],
                   5446:                     lower => ['protect','menus','target','exit'],
                   5447:                   );   
1.588     raeburn  5448:     %titles = &Apache::lonlocal::texthash (
1.601     raeburn  5449:                   state   => 'Access status',
                   5450:                   others  => 'Hide other resources',
1.588     raeburn  5451:                   listing => 'In Contents and/or Gradebook',
                   5452:                   scope   => 'Access scope for link',
1.601     raeburn  5453:                   protect => 'Link protection',
1.597     raeburn  5454:                   menus   => 'Menu Items Displayed',
1.613     raeburn  5455:                   target  => 'Embedded?',
1.616     raeburn  5456:                   exit    => 'Exit Tool Button?',
1.588     raeburn  5457:               );
                   5458:     %options = (
1.601     raeburn  5459:                    state   => ['only','off','both'],
                   5460:                    others  => ['hide','unhide'],
1.588     raeburn  5461:                    listing => ['full','absent','grades','details','datestatus'],
                   5462:                    scope   => ['res','map','rec'],
1.601     raeburn  5463:                    protect => ['none','key','ltid','ltic'],
1.597     raeburn  5464:                    menus   => ['std','colls'],
1.613     raeburn  5465:                    target  => ['_self','_top'],
1.616     raeburn  5466:                    exit    => ['no','yes','url'],
1.588     raeburn  5467:                );
                   5468:     %optiontext = &Apache::lonlocal::texthash (
1.601     raeburn  5469:                     only       => 'deep only',
                   5470:                     off        => 'deeplink off',
                   5471:                     both       => 'regular + deep',
                   5472:                     hide       => 'Hidden',
                   5473:                     unhide     => 'Unhidden',
1.588     raeburn  5474:                     full       => 'Listed (linked) in both',
                   5475:                     absent     => 'Not listed',
                   5476:                     grades     => 'Listed in grades only',
                   5477:                     details    => 'Listed (unlinked) in both',
                   5478:                     datestatus => 'Listed (unlinked) inc. status in both',
                   5479:                     res        => 'resource only',
                   5480:                     map        => 'enclosing map/folder',
                   5481:                     rec        => 'recursive map/folder',
1.601     raeburn  5482:                     none       => 'not in use',
                   5483:                     key        => 'key access',
                   5484:                     ltic       => 'LTI access (course)',
                   5485:                     ltid       => 'LTI access (domain)' ,
1.597     raeburn  5486:                     std        => 'Standard (all menus)',
                   5487:                     colls      => 'Numbered collection',
1.614     raeburn  5488:                     _self      => 'Embedded',
1.613     raeburn  5489:                     _top       => 'Not embedded',
1.616     raeburn  5490:                     no         => 'Not in use',
                   5491:                     yes        => 'In use, no URL redirect',
                   5492:                     url        => 'In use, redirect to URL',  
1.597     raeburn  5493:                   );
                   5494:     %selectnull = &Apache::lonlocal::texthash (
1.601     raeburn  5495:                     ltic => 'Select Launcher',
                   5496:                     ltid => 'Select Launcher', 
1.597     raeburn  5497:                     colls => 'Select',
1.588     raeburn  5498:                   );
                   5499:     if ($showval =~ /,/) {
1.597     raeburn  5500:         %values=();
1.588     raeburn  5501:         @current = split(/,/,$showval);
1.601     raeburn  5502:         ($values{'state'}) = ($current[0] =~ /^(only|off|both)$/);
                   5503:         ($values{'others'}) = ($current[1] =~ /^(hide|unhide)$/);
                   5504:         ($values{'listing'}) = ($current[2] =~ /^(full|absent|grades|details|datestatus)$/);
                   5505:         ($values{'scope'}) = ($current[3] =~ /^(res|map|rec)$/);
                   5506:         ($values{'protect'}) = ($current[4] =~ /^(key:[a-zA-Z\d_.!\@#\$%^&*()+=-]+|ltic:\d+|ltid:\d+)$/);
                   5507:         ($values{'menus'}) = ($current[5] =~ /^(\d+)$/);
1.613     raeburn  5508:         ($values{'target'}) = ($current[6] =~ /^(_self|_top)$/);
1.616     raeburn  5509:         ($values{'exit'}) = ($current[7] =~ /^((?:(?:yes|url)(?:|\:[^:;"',]+))|no)$/);
1.588     raeburn  5510:     } else {
1.601     raeburn  5511:         $defaults{'state'} = 'off',
                   5512:         $defaults{'others'} = 'unhide',
1.588     raeburn  5513:         $defaults{'listing'} = 'full';
                   5514:         $defaults{'scope'} = 'res';
1.601     raeburn  5515:         $defaults{'protect'} = 'none';
1.597     raeburn  5516:         $defaults{'menus'} = '0';
1.613     raeburn  5517:         $defaults{'target'} = '_top';
1.616     raeburn  5518:         $defaults{'exit'} = 'yes';
1.588     raeburn  5519:     }
                   5520:     my $disabled;
                   5521:     if ($readonly) {
                   5522:         $disabled=' disabled="disabled"';
                   5523:     }
1.601     raeburn  5524:     my %courselti =
                   5525:         &Apache::lonnet::get_course_lti($env{'course.'.$env{'request.course.id'}.'.num'},
1.620     raeburn  5526:                                         $env{'course.'.$env{'request.course.id'}.'.domain'},
                   5527:                                         'provider');
1.601     raeburn  5528:     foreach my $item (keys(%courselti)) {
                   5529:         if (ref($courselti{$item}) eq 'HASH') {
                   5530:             $crslti{$item} = $courselti{$item}{'name'};
                   5531:         }
                   5532:     }
                   5533:     my %lti =
1.588     raeburn  5534:         &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'},
1.604     raeburn  5535:                                         'linkprot');
1.588     raeburn  5536:     foreach my $item (keys(%lti)) {
1.604     raeburn  5537:         if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) {
                   5538:             $domlti{$item} = $lti{$item}{'name'};
1.588     raeburn  5539:         }
                   5540:     }
1.597     raeburn  5541:     if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) {
                   5542:         foreach my $item (split(/;/,$env{'course.'.$env{'request.course.id'}.'.menucollections'})) {
                   5543:             my ($num,$value) = split(/\%/,$item);
                   5544:             if ($num =~ /^\d+$/) {
                   5545:                 push(@possmenus,$num);
                   5546:             }
                   5547:         }
                   5548:     }
                   5549: 
1.616     raeburn  5550:     my $output = '<input type="hidden" name="set_'.$thiskey.'" />';
                   5551:     foreach my $table ('upper','lower') {
                   5552:         next unless (ref($components{$table}) eq 'ARRAY');
                   5553:         $output .= '<table width="100%"><tr>';
                   5554:         foreach my $item (@{$components{$table}}) {
                   5555:             $output .= '<th>'.$titles{$item}.'</th>';
                   5556:         }
                   5557:         $output .= '</tr><tr>';
                   5558:         foreach my $item (@{$components{$table}}) {
                   5559:             $output .= '<td>';
                   5560:             if (($item eq 'protect') || ($item eq 'menus') || ($item eq 'exit')) {
                   5561:                 my $selected = $values{$item};
                   5562:                 foreach my $option (@{$options{$item}}) {
                   5563:                     if ($item eq 'protect') { 
                   5564:                         if ($option eq 'ltid') {
                   5565:                             next unless (keys(%domlti));
                   5566:                         } elsif ($option eq 'ltic') {
                   5567:                             next unless (keys(%crslti));
                   5568:                         }
                   5569:                     } elsif (($item eq 'menus') && ($option eq 'colls')) {
                   5570:                         next unless (@possmenus);
                   5571:                     }
                   5572:                     my $checked;
                   5573:                     if ($item eq 'menus') {
                   5574:                         if (($selected =~ /^\d+$/) && (@possmenus) &&
                   5575:                             (grep(/^\Q$selected\E$/,@possmenus))) {
                   5576:                             if ($option eq 'colls') {
                   5577:                                 $checked = ' checked="checked"';
                   5578:                             }
                   5579:                         } elsif (($option eq 'std') && ($selected == 0) && ($selected ne '')) {
1.597     raeburn  5580:                             $checked = ' checked="checked"';
                   5581:                         }
1.616     raeburn  5582:                     } elsif ($selected =~ /^\Q$option\E/) {
1.597     raeburn  5583:                         $checked = ' checked="checked"';
                   5584:                     }
1.616     raeburn  5585:                     my $onclick;
                   5586:                     unless ($readonly) {
                   5587:                         my $esc_key = &js_escape($thiskey);
                   5588:                         $onclick = ' onclick="toggleDeepLink(this.form,'."'$item','$esc_key'".');"';
                   5589:                     }
                   5590:                     $output .= '<span class="LC_nobreak"><label>'.
                   5591:                                '<input type="radio" name="deeplink_'.$item.'_'.$thiskey.'" value="'.$option.'"'.$onclick.$disabled.$checked.' />'."\n".
                   5592:                                $optiontext{$option}.'</label>';
                   5593:                     if (($item eq 'protect') && ($option eq 'key')) {
                   5594:                         my $visibility="hidden";
                   5595:                         my $currkey;
                   5596:                         if ($checked) {
                   5597:                             $visibility = "text";
                   5598:                             $currkey = (split(/\:/,$values{$item}))[1];
                   5599:                         }
                   5600:                         $output .= '&nbsp;'.
                   5601:                                    '<input type="'.$visibility.'" name="deeplink_'.$option.'_'.$thiskey.'" id="deeplink_'.$option.'_'.$item.'_'.$thiskey.'" value="'.$currkey.'" size="10"'.$disabled.' />';
                   5602:                     } elsif (($option eq 'ltic') || ($option eq 'ltid') || ($option eq 'colls')) {
                   5603:                         my $display="none";
                   5604:                         my ($current,$blankcheck,@possibles);
                   5605:                         if ($checked) {
                   5606:                             $display = 'inline-block';
                   5607:                             if (($option eq 'ltic') || ($option eq 'ltid'))  {
                   5608:                                 $current = (split(/\:/,$selected))[1];
                   5609:                             } else {
                   5610:                                 $current = $selected;
                   5611:                             }
1.597     raeburn  5612:                         } else {
1.616     raeburn  5613:                             $blankcheck = ' selected="selected"';
1.597     raeburn  5614:                         }
1.601     raeburn  5615:                         if ($option eq 'ltid') {
1.616     raeburn  5616:                             @possibles = keys(%domlti);
1.601     raeburn  5617:                         } elsif ($option eq 'ltic') {
1.616     raeburn  5618:                             @possibles = keys(%crslti); 
                   5619:                         } else {
                   5620:                             @possibles = @possmenus;
                   5621:                         }
                   5622:                         $output .= '<div id="deeplinkdiv_'.$option.'_'.$item.'_'.$thiskey.'"'.
                   5623:                                    ' style="display: '.$display.'">&nbsp;<select name="'.
                   5624:                                    'deeplink_'.$option.'_'.$thiskey.'"'.$disabled.'>';
                   5625:                         if (@possibles > 1) {
                   5626:                             $output .= '<option value=""'.$blankcheck.'>'.$selectnull{$option}.
                   5627:                                        '</option>'."\n";
                   5628:                         }
                   5629:                         foreach my $poss (sort { $a <=> $b } @possibles) {
                   5630:                             my $selected;
                   5631:                             if (($poss == $current) || (scalar(@possibles) ==1)) {
                   5632:                                 $selected = ' selected="selected"';
                   5633:                             }
                   5634:                             my $shown = $poss;
                   5635:                             if ($option eq 'ltid') {
                   5636:                                 $shown = $domlti{$poss};
                   5637:                             } elsif ($option eq 'ltic') {
                   5638:                                 $shown = $crslti{$poss};
                   5639:                             }
                   5640:                             $output .= '<option value="'.$poss.'"'.$selected.'>'.$shown.'</option>';
                   5641:                         }
                   5642:                         $output .= '</select></div>';
                   5643:                     }
                   5644:                     $output .= '</span> ';
                   5645:                 }
                   5646:                 if ($item eq 'exit') {
                   5647:                     my $exitsty = 'none';
                   5648:                     my $displayval;
                   5649:                     if ($values{$item} =~ /^(yes|url)/) { 
                   5650:                         $exitsty = 'inline-block';
                   5651:                         my $currval = (split(/\:/,$values{$item}))[1];
                   5652:                         if ($currval eq '') {
                   5653:                             $displayval = 'Exit Tool';
                   5654:                         } else {
                   5655:                             $displayval = $currval;
1.597     raeburn  5656:                         }
1.588     raeburn  5657:                     }
1.616     raeburn  5658:                     $output .= '<div id="deeplinkdiv_'.$item.'_'.$thiskey.'"'.
                   5659:                                ' style="display: '.$exitsty.'"><br />'.&mt('Button text').': '.
                   5660:                                '<input type="text" name="deeplink_exittext_'.$thiskey.'"'.
                   5661:                                ' id="deeplink_exittext_'.$thiskey.'" value="'.$displayval.'"'.
                   5662:                                ' size="10"'.$disabled.' /></div>';
1.588     raeburn  5663:                 }
1.616     raeburn  5664:             } else {
                   5665:                 my $selected = $values{$item};
                   5666:                 my $defsel;
                   5667:                 if ($selected eq '') {
                   5668:                     $defsel = ' selected="selected"';
                   5669:                 }
                   5670:                 $output .= '<select name="deeplink_'.$item.'_'.$thiskey.'"'.$disabled.'>'."\n".
                   5671:                            '<option value=""'.$defsel.'>'.&mt('Please select').'</option>'."\n";
                   5672:                 foreach my $option (@{$options{$item}}) {
                   5673:                     $output .= '<option value="'.$option.'"';
                   5674:                     if ($option eq $selected) {
                   5675:                         $output .= ' selected="selected"';
                   5676:                     }
                   5677:                     $output .= '>'.$optiontext{$option}.'</option>';
1.588     raeburn  5678:                 }
1.616     raeburn  5679:                 $output .= '</select>';
1.588     raeburn  5680:             }
1.616     raeburn  5681:             $output .= '</td>';
                   5682:         }
                   5683:         $output .= '</tr></table>'."\n";
                   5684:         if ($table eq 'upper') {
                   5685:             $output .= '<br />';
1.588     raeburn  5686:         }
                   5687:     }
                   5688:     return $output;
                   5689: }
                   5690: 
1.622     raeburn  5691: sub string_grace_selector {
                   5692:     my ($thiskey, $showval, $readonly) = @_;
                   5693:     my $addmore;
                   5694:     unless ($readonly) {
                   5695:         $addmore = "\n".'<button class="LC_add_grace_button">'.&mt('Add more').'</button>';
                   5696:     }
                   5697:     my $output = '<input type="hidden" name="set_'.$thiskey.'" value="" />'.
                   5698:                  '<div class="LC_string_grace_wrap" id="LC_string_grace_'.$thiskey.'">'."\n".
                   5699:                  '<div class="LC_string_grace_inner">'."\n";
                   5700:     if ($showval ne '') {
                   5701:         my @current;
                   5702:         if ($showval =~ /,/) {
                   5703:             @current = split(/,/,$showval);
                   5704:         } else {
                   5705:             @current = ($showval);
                   5706:         }
                   5707:         my $num = scalar(@current);	
                   5708:         foreach my $item (@current) {
                   5709:             my ($delta,$fraction,$gradational) = split(/:/,$item);
                   5710:             if (($delta =~ /^\d+$/) && ($fraction =~ /^(0|1)\.?\d*$/) && 
                   5711:                 (($gradational eq 1) || ($gradational eq '0'))) {
                   5712:                 my $gradchk = '';
                   5713:                 if ($gradational) {
                   5714:                     $gradchk = ' checked="checked"';
                   5715:                 }
                   5716:                 $output .= &grace_form($thiskey,$delta,$fraction,$gradchk,
                   5717:                                        $readonly);
                   5718:             }
                   5719:         }
                   5720:     } elsif (!$readonly) {
                   5721:         $output .= &grace_form($thiskey,'','','',$readonly);
                   5722:     }
                   5723:     $output .= '</div>'.$addmore.'</div>';
                   5724:     return $output;
                   5725: }
                   5726: 
                   5727: sub grace_form {
                   5728:     my ($thiskey,$delta,$fraction,$gradchkon,$readonly) = @_;
                   5729:     my $disabled;
                   5730:     if ($readonly) {
                   5731:         $disabled = ' disabled="disabled"';
                   5732:     }
                   5733:     my %lt = &grace_titles();
                   5734:     my $output = '<div><input type="hidden" name="setgrace_'.$thiskey.'" value="" />'.
                   5735:                  '<fieldset class="LC_grace"><legend>'.$lt{'sinc'}.'</legend>';
1.623     raeburn  5736:     foreach my $which (['weeks', 604800, 52],
                   5737:                        ['days', 86400, 6],
1.622     raeburn  5738:                        ['hours', 3600, 23],
1.623     raeburn  5739:                        ['minutes', 60, 59]) {
1.622     raeburn  5740:         my ($name, $factor, $max) = @{ $which };
                   5741:         my $amount;
1.623     raeburn  5742:         my %select = ((map {$_ => $_} (0..$max)),
                   5743:                       'select_form_order' => [0..$max]);
                   5744:         if ($delta eq '') {
                   5745:             unshift(@{$select{'select_form_order'}},'');
                   5746:             $select{''} = '';
                   5747:             $amount = '';
                   5748:         } else {
1.622     raeburn  5749:             $amount = int($delta/$factor);
                   5750:             $delta %= $factor;
                   5751:         }
                   5752:         $output .= &Apache::loncommon::select_form($amount,$name.'_'.$thiskey,
                   5753:                                                    \%select,'',$readonly);
                   5754:         $output .= '&nbsp;'.$lt{$name}.'&nbsp;&nbsp; ';
                   5755:     }
                   5756:     $output .= '</fieldset>'.
                   5757:                '<fieldset class="LC_grace"><legend>'.$lt{'pcr'}.'</legend>'.
                   5758:                '<input type="text" size="3" name="frac_'.$thiskey.'" value="'.$fraction.'"'.$disabled.' />'.
                   5759:                '&nbsp;&nbsp;<label><input type="checkbox" value="1" name="grad_'.$thiskey.'"'.$gradchkon.$disabled.' />'.
                   5760:                $lt{'grad'}.'</label></fieldset>';
                   5761:     unless ($readonly) {
                   5762:         $output .= '<a href="#" class="LC_remove_grace">'.$lt{'remo'}.'</a>';
                   5763:     }
                   5764:     $output .= '</div>'."\n";
                   5765:     return $output;
                   5766: }
                   5767: 
                   5768: sub grace_titles {
                   5769:     return &Apache::lonlocal::texthash (
                   5770:                                          sinc => 'Time past due',
                   5771:                                          remo => 'Remove',
                   5772:                                          pcr => 'Partial credit',
                   5773:                                          grad => 'gradual',
1.623     raeburn  5774:                                          weeks => 'weeks',
1.622     raeburn  5775:                                          days => 'days',
                   5776:                                          hours => 'hours',
                   5777:                                          minutes => 'minutes',
                   5778:     );
                   5779: }
1.560     damieng  5780: 
                   5781: { # block using some constants related to parameter types (overview mode)
                   5782: 
1.446     bisitz   5783: my %strings =
1.383     albertel 5784:     (
                   5785:      'string_yesno'
                   5786:              => [[ 'yes', 'Yes' ],
1.560     damieng  5787:                  [ 'no', 'No' ]],
1.383     albertel 5788:      'string_problemstatus'
                   5789:              => [[ 'yes', 'Yes' ],
1.473     amueller 5790:          [ 'answer', 'Yes, and show correct answer if they exceed the maximum number of tries.' ],
                   5791:          [ 'no', 'No, don\'t show correct/incorrect feedback.' ],
                   5792:          [ 'no_feedback_ever', 'No, show no feedback at all.' ]],
1.504     raeburn  5793:      'string_questiontype'
                   5794:              => [[ 'problem', 'Standard Problem'],
                   5795:                  [ 'survey', 'Survey'],
                   5796:                  [ 'anonsurveycred', 'Anonymous Survey (credit for submission)'],
1.530     bisitz   5797:                  [ 'exam', 'Bubblesheet Exam'],
1.504     raeburn  5798:                  [ 'anonsurvey', 'Anonymous Survey'],
                   5799:                  [ 'randomizetry', 'New Randomization Each N Tries (default N=1)'],
                   5800:                  [ 'practice', 'Practice'],
                   5801:                  [ 'surveycred', 'Survey (credit for submission)']],
1.514     raeburn  5802:      'string_lenient'
                   5803:              => [['yes', 'Yes' ],
                   5804:                  [ 'no', 'No' ],
1.549     raeburn  5805:                  [ 'default', 'Default - only bubblesheet grading is lenient' ],
                   5806:                  [ 'weighted', 'Yes, weighted (optionresponse in checkbox mode)' ]],
1.521     raeburn  5807:      'string_discussvote'
                   5808:              => [['yes','Yes'],
                   5809:                  ['notended','Yes, unless discussion ended'],
                   5810:                  ['no','No']],
1.549     raeburn  5811:      'string_ip'
                   5812:              => [['_allowfrom_','Hostname(s), or IP(s) from which access is allowed'],
1.587     raeburn  5813:                  ['_denyfrom_','Hostname(s) or IP(s) from which access is disallowed']], 
                   5814:      'string_deeplink'
1.616     raeburn  5815:              => [['on','Set choices for link protection, resource listing, access scope, shown menu items, embedding, and exit link']],
1.621     raeburn  5816:      'string_tex'
                   5817:              => [['tth', 'tth (TeX to HTML)'],
                   5818:                  ['mathjax', 'MathJax']],
1.622     raeburn  5819:      'string_grace'
                   5820:              => [['on','Set grading scale and grace period for submissions after due date']],
1.587     raeburn  5821:     );
                   5822:    
1.383     albertel 5823: 
1.549     raeburn  5824: my %stringmatches = (
                   5825:          'string_lenient'
                   5826:               => [['weighted','^\-?[.\d]+,\-?[.\d]+,\-?[.\d]+,\-?[.\d]+$'],],
                   5827:          'string_ip'
                   5828:               => [['_allowfrom_','[^\!]+'],
                   5829:                   ['_denyfrom_','\!']],
1.588     raeburn  5830:          'string_deeplink'
1.616     raeburn  5831:               => [['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  5832:          'string_grace'
                   5833:               => [['on','^\d+,(0|1)\.?\d*,(0|1)']],
1.549     raeburn  5834:     );
                   5835: 
                   5836: my %stringtypes = (
                   5837:                     type         => 'string_questiontype',
                   5838:                     lenient      => 'string_lenient',
                   5839:                     retrypartial => 'string_yesno',
                   5840:                     discussvote  => 'string_discussvote',
                   5841:                     examcode     => 'string_examcode',
                   5842:                     acc          => 'string_ip',
1.587     raeburn  5843:                     deeplink     => 'string_deeplink',
1.622     raeburn  5844:                     grace        => 'string_grace',
1.621     raeburn  5845:                     texdisplay   => 'string_tex',
1.549     raeburn  5846:                   );
                   5847: 
1.563     damieng  5848: # Returns the possible values and titles for a given string type, or undef if there are none.
                   5849: # Used by courseprefs.
                   5850: #
                   5851: # @param {string} $string_type - a parameter type for strings
                   5852: # @returns {array reference} - 2D array, containing values and English titles
1.505     raeburn  5853: sub standard_string_options {
                   5854:     my ($string_type) = @_;
                   5855:     if (ref($strings{$string_type}) eq 'ARRAY') {
                   5856:         return $strings{$string_type};
                   5857:     }
                   5858:     return;
                   5859: }
1.383     albertel 5860: 
1.563     damieng  5861: # Returns regular expressions to match kinds of string types, or undef if there are none.
                   5862: #
                   5863: # @param {string} $string_type - a parameter type for strings
                   5864: # @returns {array reference}  - 2D array, containing regular expression names and regular expressions
1.549     raeburn  5865: sub standard_string_matches {
                   5866:     my ($string_type) = @_;
                   5867:     if (ref($stringmatches{$string_type}) eq 'ARRAY') {
                   5868:         return $stringmatches{$string_type};
                   5869:     }
                   5870:     return;
                   5871: }
                   5872: 
1.563     damieng  5873: # Returns a parameter type for a given parameter with a string type, or undef if not known.
                   5874: #
                   5875: # @param {string} $name - parameter name
                   5876: # @returns {string}
1.549     raeburn  5877: sub get_stringtype {
                   5878:     my ($name) = @_;
                   5879:     if (exists($stringtypes{$name})) {
                   5880:         return $stringtypes{$name};
                   5881:     }
                   5882:     return;
                   5883: }
                   5884: 
1.563     damieng  5885: # Returns HTML to edit a string parameter.
                   5886: #
                   5887: # @param {string} $thistype - parameter type
                   5888: # @param {string} $thiskey - parameter key
                   5889: # @param {string} $showval - parameter current value
                   5890: # @param {string} $name - parameter name
                   5891: # @param {boolean} $readonly - true if the values should not be made editable
                   5892: # @returns {string}
1.383     albertel 5893: sub string_selector {
1.552     raeburn  5894:     my ($thistype, $thiskey, $showval, $name, $readonly) = @_;
1.446     bisitz   5895: 
1.383     albertel 5896:     if (!exists($strings{$thistype})) {
1.552     raeburn  5897:         return &default_selector($thiskey,$showval,$readonly);
1.383     albertel 5898:     }
                   5899: 
1.504     raeburn  5900:     my %skiptype;
1.514     raeburn  5901:     if (($thistype eq 'string_questiontype') || 
1.560     damieng  5902:             ($thistype eq 'string_lenient') ||
                   5903:             ($thistype eq 'string_discussvote') ||
                   5904:             ($thistype eq 'string_ip') ||
1.588     raeburn  5905:             ($thistype eq 'string_deeplink') ||
1.621     raeburn  5906:             ($thistype eq 'string_tex') ||
1.622     raeburn  5907:             ($thistype eq 'string_grace') ||
1.560     damieng  5908:             ($name eq 'retrypartial')) {
1.504     raeburn  5909:         my ($got_chostname,$chostname,$cmajor,$cminor); 
                   5910:         foreach my $possibilities (@{ $strings{$thistype} }) {
                   5911:             next unless (ref($possibilities) eq 'ARRAY');
1.514     raeburn  5912:             my ($parmval, $description) = @{ $possibilities };
1.549     raeburn  5913:             my $parmmatch;
                   5914:             if (ref($stringmatches{$thistype}) eq 'ARRAY') {
                   5915:                 foreach my $item (@{$stringmatches{$thistype}}) {
                   5916:                     if (ref($item) eq 'ARRAY') {
                   5917:                         if ($parmval eq $item->[0]) {
                   5918:                             $parmmatch = $parmval;
                   5919:                             $parmval = '';
                   5920:                             last;
                   5921:                         }
                   5922:                     }
                   5923:                 }
                   5924:             }
                   5925:             my $needsrelease=$Apache::lonnet::needsrelease{"parameter:$name:$parmval:$parmmatch"}; 
1.504     raeburn  5926:             if ($needsrelease) {
                   5927:                 unless ($got_chostname) {
1.514     raeburn  5928:                     ($chostname,$cmajor,$cminor)=&parameter_release_vars();
1.504     raeburn  5929:                     $got_chostname = 1;
                   5930:                 }
1.557     raeburn  5931:                 my $needsnewer=&parameter_releasecheck($name,$parmval,$parmmatch,undef,
1.549     raeburn  5932:                                                        $needsrelease,$cmajor,$cminor);
1.504     raeburn  5933:                 if ($needsnewer) {
1.549     raeburn  5934:                     if ($parmmatch ne '') {
                   5935:                         $skiptype{$parmmatch} = 1;
                   5936:                     } elsif ($parmval ne '') {
                   5937:                         $skiptype{$parmval} = 1;
                   5938:                     }
1.504     raeburn  5939:                 }
                   5940:             }
                   5941:         }
                   5942:     }
1.549     raeburn  5943: 
                   5944:     if ($thistype eq 'string_ip') {
1.622     raeburn  5945:         return &string_ip_selector($thiskey,$showval,$readonly);
                   5946:     } elsif ($thistype eq 'string_grace') {
                   5947:         return &string_grace_selector($thiskey,$showval,$readonly);
1.588     raeburn  5948:     } elsif ($thistype eq 'string_deeplink') {
                   5949:         return &string_deeplink_selector($thiskey,$showval,$readonly);
1.549     raeburn  5950:     }
1.504     raeburn  5951: 
1.552     raeburn  5952:     my ($result,$disabled);
                   5953: 
                   5954:     if ($readonly) {
                   5955:         $disabled = ' disabled="disabled"';
                   5956:     }
1.504     raeburn  5957:     my $numinrow = 3;
                   5958:     if ($thistype eq 'string_problemstatus') {
                   5959:         $numinrow = 2;
                   5960:     } elsif ($thistype eq 'string_questiontype') {
                   5961:         if (keys(%skiptype) > 0) {
                   5962:              $numinrow = 4;
                   5963:         }
                   5964:     }
                   5965:     my $rem;
                   5966:     if (ref($strings{$thistype}) eq 'ARRAY') {
                   5967:         my $i=0;
                   5968:         foreach my $possibilities (@{ $strings{$thistype} }) {
                   5969:             next unless (ref($possibilities) eq 'ARRAY');
                   5970:             my ($name, $description) = @{ $possibilities };
1.549     raeburn  5971:             next if ($skiptype{$name});
1.504     raeburn  5972:             $rem = $i%($numinrow);
                   5973:             if ($rem == 0) {
                   5974:                 if ($i > 0) {
                   5975:                     $result .= '</tr>';
                   5976:                 }
                   5977:                 $result .= '<tr>';
                   5978:             }
1.549     raeburn  5979:             my $colspan;
                   5980:             if ($i == @{ $strings{$thistype} }-1) {
                   5981:                 $rem = @{ $strings{$thistype} }%($numinrow);
                   5982:                 if ($rem) {
                   5983:                     my $colsleft = $numinrow - $rem;
                   5984:                     if ($colsleft) {
                   5985:                         $colspan = $colsleft+1;
                   5986:                         $colspan = ' colspan="'.$colspan.'"';
                   5987:                     }
                   5988:                 }
                   5989:             }
                   5990:             my ($add,$onchange,$css_class);
                   5991:             if ($thistype eq 'string_lenient') {
                   5992:                 if ($name eq 'weighted') {
                   5993:                     my $display;
                   5994:                     my %relatives = &Apache::lonlocal::texthash(
                   5995:                                         corrchkd     => 'Correct (checked)',
                   5996:                                         corrunchkd   => 'Correct (unchecked)',
                   5997:                                         incorrchkd   => 'Incorrect (checked)',
                   5998:                                         incorrunchkd => 'Incorrect (unchecked)',
                   5999:                     );
                   6000:                     my %textval = (
                   6001:                                     corrchkd     => '1.0',
                   6002:                                     corrunchkd   => '1.0',
                   6003:                                     incorrchkd   => '0.0',
                   6004:                                     incorrunchkd => '0.0',
                   6005:                     );
                   6006:                     if ($showval =~ /^([\-\d\.]+)\,([\-\d\.]+)\,([\-\d\.]+)\,([\-\d\.]+)$/) {
                   6007:                         $textval{'corrchkd'} = $1;
                   6008:                         $textval{'corrunchkd'} = $2;
                   6009:                         $textval{'incorrchkd'} = $3;
                   6010:                         $textval{'incorrunchkd'} = $4;
                   6011:                         $display = 'inline';
                   6012:                         $showval = $name;
                   6013:                     } else {
                   6014:                         $display = 'none';
                   6015:                     }
                   6016:                     $add = ' <div id="LC_parmtext_'.$thiskey.'" style="display:'.$display.'"><table>'.
                   6017:                            '<tr><th colspan="2">'.&mt("Foil's submission status").'</th><th>'.&mt('Points').'</th></tr>';  
                   6018:                     foreach my $reltype ('corrchkd','corrunchkd','incorrchkd','incorrunchkd') {
                   6019:                         $add .= '<tr><td>&nbsp;</td><td>'.$relatives{$reltype}.'</td>'."\n".
                   6020:                                 '<td><input type="text" name="settext_'.$thiskey.'"'.
1.552     raeburn  6021:                                 ' value="'.$textval{$reltype}.'" size="3"'.$disabled.' />'.
1.549     raeburn  6022:                                 '</td></tr>';
                   6023:                     }
                   6024:                     $add .= '</table></div>'."\n";
                   6025:                 }
                   6026:                 $onchange = ' onclick="javascript:toggleParmTextbox(this.form,'."'$thiskey'".');"';
                   6027:                 $css_class = ' class="LC_lenient_radio"';
                   6028:             }
                   6029:             $result .= '<td class="LC_left_item"'.$colspan.'>'.
1.504     raeburn  6030:                        '<span class="LC_nobreak"><label>'.
                   6031:                        '<input type="radio" name="set_'.$thiskey.
1.552     raeburn  6032:                        '" value="'.$name.'"'.$onchange.$css_class.$disabled;
1.504     raeburn  6033:             if ($showval eq $name) {
                   6034:                 $result .= ' checked="checked"';
                   6035:             }
1.549     raeburn  6036:             $result .= ' />'.&mt($description).'</label>'.$add.'</span></td>';
1.504     raeburn  6037:             $i++;
                   6038:         }
                   6039:         $result .= '</tr>';
1.473     amueller 6040:     }
1.504     raeburn  6041:     if ($result) {
                   6042:         $result = '<table border="0">'.$result.'</table>';
1.383     albertel 6043:     }
                   6044:     return $result;
                   6045: }
                   6046: 
1.554     raeburn  6047: my %intervals =
                   6048:     (
                   6049:      'date_interval'
                   6050:              => [[ 'done', 'Yes' ],
1.558     raeburn  6051:                  [ 'done_proctor', 'Yes, with proctor key'],                  
1.554     raeburn  6052:                  [ '', 'No' ]],
                   6053:     );
                   6054: 
                   6055: my %intervalmatches = (
                   6056:          'date_interval'
1.559     raeburn  6057:               => [['done','\d+_done(|\:[^\:]+\:)$'],
                   6058:                   ['done_proctor','\d+_done(|\:[^\:]+\:)_proctor_']],
1.554     raeburn  6059:     );
                   6060: 
                   6061: my %intervaltypes = (
                   6062:                       interval => 'date_interval',
                   6063:     );
                   6064: 
1.563     damieng  6065: # Returns regular expressions to match kinds of interval type, or undef if there are none.
                   6066: #
                   6067: # @param {string} $interval_type - a parameter type for intervals
                   6068: # @returns {array reference}  - 2D array, containing regular expression names and regular expressions
1.554     raeburn  6069: sub standard_interval_matches {
                   6070:     my ($interval_type) = @_;
                   6071:     if (ref($intervalmatches{$interval_type}) eq 'ARRAY') {
                   6072:         return $intervalmatches{$interval_type};
                   6073:     }
                   6074:     return;
                   6075: }
                   6076: 
1.563     damieng  6077: # Returns a parameter type for a given parameter with an interval type, or undef if not known.
                   6078: #
                   6079: # @param {string} $name - parameter name
                   6080: # @returns {string}
1.554     raeburn  6081: sub get_intervaltype {
                   6082:     my ($name) = @_;
                   6083:     if (exists($intervaltypes{$name})) {
                   6084:         return $intervaltypes{$name};
                   6085:     }
                   6086:     return;
                   6087: }
                   6088: 
1.563     damieng  6089: # Returns the possible values and titles for a given interval type, or undef if there are none.
                   6090: # Used by courseprefs.
                   6091: #
                   6092: # @param {string} $interval_type - a parameter type for intervals
                   6093: # @returns {array reference} - 2D array, containing values and English titles
1.554     raeburn  6094: sub standard_interval_options {
                   6095:     my ($interval_type) = @_;
                   6096:     if (ref($intervals{$interval_type}) eq 'ARRAY') {
                   6097:         return $intervals{$interval_type};
                   6098:     }
                   6099:     return;
                   6100: }
                   6101: 
1.563     damieng  6102: # Returns HTML to edit a date interval parameter.
                   6103: #
                   6104: # @param {string} $thiskey - parameter key
                   6105: # @param {string} $name - parameter name
                   6106: # @param {string} $showval - parameter current value
                   6107: # @param {boolean} $readonly - true if the values should not be made editable
                   6108: # @returns {string}
1.554     raeburn  6109: sub date_interval_selector {
                   6110:     my ($thiskey, $name, $showval, $readonly) = @_;
                   6111:     my ($result,%skipval);
                   6112:     if ($name eq 'interval') {
                   6113:         my $intervaltype = &get_intervaltype($name);
                   6114:         my ($got_chostname,$chostname,$cmajor,$cminor);
                   6115:         foreach my $possibilities (@{ $intervals{$intervaltype} }) {
                   6116:             next unless (ref($possibilities) eq 'ARRAY');
                   6117:             my ($parmval, $description) = @{ $possibilities };
                   6118:             my $parmmatch;
                   6119:             if (ref($intervalmatches{$intervaltype}) eq 'ARRAY') {
                   6120:                 foreach my $item (@{$intervalmatches{$intervaltype}}) {
                   6121:                     if (ref($item) eq 'ARRAY') {
                   6122:                         if ($parmval eq $item->[0]) {
                   6123:                             $parmmatch = $parmval;
                   6124:                             $parmval = '';
                   6125:                             last;
                   6126:                         }
                   6127:                     }
                   6128:                 }
                   6129:             }
                   6130:             my $needsrelease=$Apache::lonnet::needsrelease{"parameter:$name:$parmval:$parmmatch"};
                   6131:             if ($needsrelease) {
                   6132:                 unless ($got_chostname) {
                   6133:                     ($chostname,$cmajor,$cminor)=&parameter_release_vars();
                   6134:                     $got_chostname = 1;
                   6135:                 }
1.557     raeburn  6136:                 my $needsnewer=&parameter_releasecheck($name,$parmval,$parmmatch,undef,
1.554     raeburn  6137:                                                        $needsrelease,$cmajor,$cminor);
                   6138:                 if ($needsnewer) {
                   6139:                     if ($parmmatch ne '') {
                   6140:                         $skipval{$parmmatch} = 1;
                   6141:                     } elsif ($parmval ne '') {
                   6142:                         $skipval{$parmval} = 1;
                   6143:                     }
                   6144:                 }
                   6145:             }
                   6146:         }
                   6147:     }
                   6148: 
                   6149:     my $currval = $showval;
                   6150:     foreach my $which (['days', 86400, 31],
                   6151:                ['hours', 3600, 23],
                   6152:                ['minutes', 60, 59],
                   6153:                ['seconds',  1, 59]) {
1.560     damieng  6154:         my ($name, $factor, $max) = @{ $which };
                   6155:         my $amount = int($showval/$factor);
                   6156:         $showval  %= $factor;
                   6157:         my %select = ((map {$_ => $_} (0..$max)),
                   6158:                 'select_form_order' => [0..$max]);
1.611     raeburn  6159:         if ($currval eq '') {
                   6160:             unshift(@{$select{'select_form_order'}},'');
                   6161:             $select{''} = '';
                   6162:             $amount = '';
                   6163:         }
1.560     damieng  6164:         $result .= &Apache::loncommon::select_form($amount,$name.'_'.$thiskey,
                   6165:                             \%select,'',$readonly);
                   6166:         $result .= ' '.&mt($name);
1.554     raeburn  6167:     }
                   6168:     if ($name eq 'interval') {
                   6169:         unless ($skipval{'done'}) {
                   6170:             my $checkedon = '';
1.611     raeburn  6171:             my $checkedoff = '';
1.558     raeburn  6172:             my $checkedproc = '';
                   6173:             my $currproctorkey = '';
                   6174:             my $currprocdisplay = 'hidden';
1.559     raeburn  6175:             my $currdonetext = &mt('Done');
                   6176:             if ($currval =~ /^(?:\d+)_done$/) {
                   6177:                 $checkedon = ' checked="checked"';
                   6178:             } elsif ($currval =~ /^(?:\d+)_done\:([^\:]+)\:$/) {
                   6179:                 $currdonetext = $1;
1.554     raeburn  6180:                 $checkedon = ' checked="checked"';
1.558     raeburn  6181:             } elsif ($currval =~ /^(?:\d+)_done_proctor_(.+)$/) {
                   6182:                 $currproctorkey = $1;
                   6183:                 $checkedproc = ' checked="checked"';
                   6184:                 $currprocdisplay = 'text';
1.559     raeburn  6185:             } elsif ($currval =~ /^(?:\d+)_done\:([^\:]+)\:_proctor_(.+)$/) {
                   6186:                 $currdonetext = $1;
                   6187:                 $currproctorkey = $2;
                   6188:                 $checkedproc = ' checked="checked"';
                   6189:                 $currprocdisplay = 'text';
1.611     raeburn  6190:             } elsif ($currval ne '') {
                   6191:                 $checkedoff = ' checked="checked"';
                   6192:             } else {
                   6193:                 $currdonetext = '';
1.554     raeburn  6194:             }
1.558     raeburn  6195:             my $onclick = ' onclick="toggleSecret(this.form,'."'done_','$thiskey'".');"';
1.567     raeburn  6196:             my $disabled;
                   6197:             if ($readonly) {
                   6198:                 $disabled = ' disabled="disabled"';
                   6199:             }
1.558     raeburn  6200:             $result .= '<br /><span class="LC_nobreak">'.&mt('Include "done" button').
1.567     raeburn  6201:                        '<label><input type="radio" value="" name="done_'.$thiskey.'"'.$checkedoff.$onclick.$disabled.' />'.
1.558     raeburn  6202:                        &mt('No').'</label>'.('&nbsp;'x2).
1.567     raeburn  6203:                        '<label><input type="radio" value="_done" name="done_'.$thiskey.'"'.$checkedon.$onclick.$disabled.' />'.
1.558     raeburn  6204:                        &mt('Yes').'</label>'.('&nbsp;'x2).
1.567     raeburn  6205:                        '<label><input type="radio" value="_done_proctor" name="done_'.$thiskey.'"'.$checkedproc.$onclick.$disabled.' />'.
1.558     raeburn  6206:                        &mt('Yes, with proctor key').'</label>'.
                   6207:                        '<input type="'.$currprocdisplay.'" id="done_'.$thiskey.'_proctorkey" '.
1.567     raeburn  6208:                        'name="done_'.$thiskey.'_proctorkey" value="'.&HTML::Entities::encode($currproctorkey,'"<>&').'"'.$disabled.' /></span><br />'.
1.559     raeburn  6209:                        '<span class="LC_nobreak">'.&mt('Button text').': '.
1.611     raeburn  6210:                        '<input type="text" name="done_'.$thiskey.'_buttontext" id="done_'.$thiskey.'_buttontext" value="'.
                   6211:                        &HTML::Entities::encode($currdonetext,'"<>&').'"'.$disabled.' /></span>';
1.554     raeburn  6212:         }
                   6213:     }
                   6214:     unless ($readonly) {
                   6215:         $result .= '<input type="hidden" name="dateinterval_'.$thiskey.'" />';
                   6216:     }
                   6217:     return $result;
                   6218: }
                   6219: 
1.563     damieng  6220: # Returns HTML with a warning if a parameter requires a more recent version of LON-CAPA.
                   6221: #
                   6222: # @param {string} $name - parameter name
                   6223: # @param {string} $namematch - parameter level name (recognized: resourcelevel|maplevel|maplevelrecurse|courselevel)
                   6224: # @param {string} $value - parameter value
                   6225: # @param {string} $chostname - course server name
                   6226: # @param {integer} $cmajor - major version number
                   6227: # @param {integer} $cminor - minor version number
                   6228: # @param {string} $needsrelease - release version needed (major.minor)
                   6229: # @returns {string}
1.549     raeburn  6230: sub oldversion_warning {
1.557     raeburn  6231:     my ($name,$namematch,$value,$chostname,$cmajor,$cminor,$needsrelease) = @_;
                   6232:     my $standard_name = &standard_parameter_names($name);
                   6233:     if ($namematch) {
                   6234:         my $level = &standard_parameter_levels($namematch);
                   6235:         my $msg = '';
                   6236:         if ($level) {
                   6237:             $msg = &mt('[_1] was [_2]not[_3] set at the level of: [_4].',
                   6238:                        $standard_name,'<b>','</b>','"'.$level.'"');
                   6239:         } else {
                   6240:             $msg = &mt('[_1] was [_2]not[_3] set.',
                   6241:                       $standard_name,'<b>','</b>');
                   6242:         }
                   6243:         return '<p class="LC_warning">'.$msg.'<br />'.
                   6244:                &mt('LON-CAPA version ([_1]) installed on home server ([_2]) does not meet version requirements ([_3] or newer).',
                   6245:                    $cmajor.'.'.$cminor,$chostname,
                   6246:                    $needsrelease).
                   6247:                    '</p>';
                   6248:     }
1.549     raeburn  6249:     my $desc;
                   6250:     my $stringtype = &get_stringtype($name);
                   6251:     if ($stringtype ne '') {
                   6252:         if ($name eq 'examcode') {
                   6253:             $desc = $value;
                   6254:         } elsif (ref($strings{$stringtypes{$name}}) eq 'ARRAY') {
                   6255:             foreach my $possibilities (@{ $strings{$stringtypes{$name}} }) {
                   6256:                 next unless (ref($possibilities) eq 'ARRAY');
                   6257:                 my ($parmval, $description) = @{ $possibilities };
                   6258:                 my $parmmatch;
                   6259:                 if (ref($stringmatches{$stringtypes{$name}}) eq 'ARRAY') {
                   6260:                     foreach my $item (@{$stringmatches{$stringtypes{$name}}}) {
                   6261:                         if (ref($item) eq 'ARRAY') {
                   6262:                             my ($regexpname,$pattern) = @{$item};
                   6263:                             if ($parmval eq $regexpname) {
                   6264:                                 if ($value =~ /$pattern/) {
                   6265:                                     $desc = $description; 
                   6266:                                     $parmmatch = 1;
                   6267:                                     last;
                   6268:                                 }
                   6269:                             }
                   6270:                         }
                   6271:                     }
                   6272:                     last if ($parmmatch);
                   6273:                 } elsif ($parmval eq $value) {
                   6274:                     $desc = $description;
                   6275:                     last;
                   6276:                 }
                   6277:             }
                   6278:         }
                   6279:     } elsif (($name eq 'printstartdate') || ($name eq 'printenddate')) {
                   6280:         my $now = time;
                   6281:         if ($value =~ /^\d+$/) {
                   6282:             if ($name eq 'printstartdate') {
                   6283:                 if ($value > $now) {
                   6284:                     $desc = &Apache::lonlocal::locallocaltime($value);
                   6285:                 }
                   6286:             } elsif ($name eq 'printenddate') {
                   6287:                 if ($value < $now) {
                   6288:                     $desc = &Apache::lonlocal::locallocaltime($value);
                   6289:                 }
                   6290:             }
                   6291:         }
                   6292:     }
                   6293:     return '<p class="LC_warning">'.
1.557     raeburn  6294:        &mt('[_1] was [_2]not[_3] set to [_4].',
                   6295:            $standard_name,'<b>','</b>','"'.$desc.'"').'<br />'.
                   6296:        &mt('LON-CAPA version ([_1]) installed on home server ([_2]) does not meet version requirements ([_3] or newer).',
                   6297:        $cmajor.'.'.$cminor,$chostname,
                   6298:        $needsrelease).
                   6299:        '</p>';
1.549     raeburn  6300: }
                   6301: 
1.560     damieng  6302: } # end of block using some constants related to parameter types
                   6303: 
1.549     raeburn  6304: 
1.563     damieng  6305: 
                   6306: # Shifts all start and end dates in the current course by $shift.
1.389     www      6307: #
1.563     damieng  6308: # @param {integer} $shift - time to shift, in seconds
                   6309: # @returns {string} - error name or 'ok'
1.389     www      6310: sub dateshift {
1.594     raeburn  6311:     my ($shift,$numchanges)=@_;
1.389     www      6312:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6313:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.594     raeburn  6314:     my $sec = $env{'request.course.sec'};
1.595     raeburn  6315:     my $secgrpregex;
                   6316:     if ($sec ne '') {
                   6317:         my @groups;
                   6318:         if ($env{'request.course.groups'} ne '') {
                   6319:             @groups = split(/:/,$env{'request.course.groups'});
                   6320:         }
                   6321:         if (@groups) {
                   6322:             $secgrpregex = '(?:'.join('|',($sec,@groups)).')';
                   6323:         } else {
                   6324:             $secgrpregex = $sec;
                   6325:         }
                   6326:     }
1.389     www      6327:     my %data=&Apache::lonnet::dump('resourcedata',$dom,$crs);
                   6328: # ugly retro fix for broken version of types
1.548     raeburn  6329:     foreach my $key (keys(%data)) {
1.389     www      6330:         if ($key=~/\wtype$/) {
                   6331:             my $newkey=$key;
                   6332:             $newkey=~s/type$/\.type/;
                   6333:             $data{$newkey}=$data{$key};
                   6334:             delete $data{$key};
                   6335:         }
                   6336:     }
1.391     www      6337:     my %storecontent=();
1.389     www      6338: # go through all parameters and look for dates
1.548     raeburn  6339:     foreach my $key (keys(%data)) {
1.389     www      6340:        if ($data{$key.'.type'}=~/^date_(start|end)$/) {
1.594     raeburn  6341:           if ($sec ne '') {
1.595     raeburn  6342:               next unless ($key =~ /^$env{'request.course.id'}\.\[$secgrpregex\]\./);
1.594     raeburn  6343:           }
1.389     www      6344:           my $newdate=$data{$key}+$shift;
1.594     raeburn  6345:           $$numchanges ++;
1.391     www      6346:           $storecontent{$key}=$newdate;
1.389     www      6347:        }
                   6348:     }
1.391     www      6349:     my $reply=&Apache::lonnet::cput
                   6350:                 ('resourcedata',\%storecontent,$dom,$crs);
                   6351:     if ($reply eq 'ok') {
                   6352:        &log_parmset(\%storecontent);
                   6353:     }
                   6354:     &Apache::lonnet::devalidatecourseresdata($crs,$dom);
                   6355:     return $reply;
1.389     www      6356: }
                   6357: 
1.563     damieng  6358: # Overview mode UI to edit course parameters.
                   6359: #
                   6360: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      6361: sub newoverview {
1.568     raeburn  6362:     my ($r,$parm_permission) = @_;
1.280     albertel 6363: 
1.208     www      6364:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6365:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6366:     my $crstype =  $env{'course.'.$env{'request.course.id'}.'.type'};
1.568     raeburn  6367:     my $readonly = 1;
                   6368:     if ($parm_permission->{'edit'}) {
                   6369:         undef($readonly);
                   6370:     }
1.414     droeschl 6371:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview',
1.473     amueller 6372:         text=>"Overview Mode"});
1.523     raeburn  6373: 
                   6374:     my %loaditems = (
1.549     raeburn  6375:                       'onload'   => "showHide_courseContent(); resize_scrollbox('mapmenuscroll','1','1'); showHideLenient();",
1.523     raeburn  6376:                     );
                   6377:     my $js = '
                   6378: <script type="text/javascript">
                   6379: // <![CDATA[
                   6380: '.
                   6381:             &Apache::lonhtmlcommon::resize_scrollbox_js('params')."\n".
                   6382:             &showhide_js()."\n".
1.549     raeburn  6383:             &toggleparmtextbox_js()."\n".
                   6384:             &validateparms_js()."\n".
                   6385:             &ipacc_boxes_js()."\n".
1.622     raeburn  6386:             &grace_js()."\n".
1.558     raeburn  6387:             &done_proctor_js()."\n".
1.588     raeburn  6388:             &deeplink_js()."\n".
1.523     raeburn  6389: '// ]]>
                   6390: </script>
                   6391: ';
1.549     raeburn  6392: 
1.523     raeburn  6393:     my $start_page = &Apache::loncommon::start_page('Set Parameters',$js,
                   6394:                                                     {'add_entries' => \%loaditems,});
1.298     albertel 6395:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview');
1.507     www      6396:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6397:     &startSettingsScreen($r,'parmset',$crstype);
1.208     www      6398:     $r->print(<<ENDOVER);
1.624   ! raeburn  6399: <form method="post" action="/adm/parmset?action=newoverview" name="parmform" id="newoverviewform">
        !          6400: <input type="hidden" name="newoverviewsubm" value="dis" id="newoverviewsubm" />
1.208     www      6401: ENDOVER
1.211     www      6402:     my @ids=();
                   6403:     my %typep=();
                   6404:     my %keyp=();
                   6405:     my %allparms=();
                   6406:     my %allparts=();
                   6407:     my %allmaps=();
                   6408:     my %mapp=();
                   6409:     my %symbp=();
                   6410:     my %maptitles=();
                   6411:     my %uris=();
                   6412:     my %keyorder=&standardkeyorder();
                   6413:     my %defkeytype=();
                   6414: 
                   6415:     my %alllevs=();
                   6416:     $alllevs{'Resource Level'}='full';
1.215     www      6417:     $alllevs{'Map/Folder Level'}='map';
1.211     www      6418:     $alllevs{'Course Level'}='general';
                   6419: 
                   6420:     my $csec=$env{'form.csec'};
1.269     raeburn  6421:     my $cgroup=$env{'form.cgroup'};
1.211     www      6422: 
                   6423:     my @pscat=&Apache::loncommon::get_env_multiple('form.pscat');
                   6424:     my $pschp=$env{'form.pschp'};
1.506     www      6425: 
1.211     www      6426:     my @psprt=&Apache::loncommon::get_env_multiple('form.psprt');
1.516     www      6427:     if (!@psprt) { $psprt[0]='all'; }
1.211     www      6428: 
1.446     bisitz   6429:     my @selected_sections =
1.473     amueller 6430:     &Apache::loncommon::get_env_multiple('form.Section');
1.211     www      6431:     @selected_sections = ('all') if (! @selected_sections);
1.374     albertel 6432:     foreach my $sec (@selected_sections) {
                   6433:         if ($sec eq 'all') {
1.211     www      6434:             @selected_sections = ('all');
                   6435:         }
                   6436:     }
1.552     raeburn  6437:     if ($env{'request.course.sec'} ne '') {
                   6438:         @selected_sections = ($env{'request.course.sec'});
                   6439:     }
1.269     raeburn  6440:     my @selected_groups =
                   6441:         &Apache::loncommon::get_env_multiple('form.Group');
1.211     www      6442: 
                   6443:     my $pssymb='';
                   6444:     my $parmlev='';
1.446     bisitz   6445: 
1.211     www      6446:     unless ($env{'form.parmlev'}) {
                   6447:         $parmlev = 'map';
                   6448:     } else {
                   6449:         $parmlev = $env{'form.parmlev'};
                   6450:     }
                   6451: 
1.446     bisitz   6452:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 6453:                 \%mapp, \%symbp,\%maptitles,\%uris,
1.603     raeburn  6454:                 \%keyorder,\%defkeytype,$pssymb);
1.211     www      6455: 
1.374     albertel 6456:     if (grep {$_ eq 'all'} (@psprt)) {
1.481     amueller 6457:         @psprt = keys(%allparts);
1.374     albertel 6458:     }
1.211     www      6459: # Menu to select levels, etc
                   6460: 
1.456     bisitz   6461:     $r->print('<div class="LC_Box">');
1.445     neumanie 6462:     #$r->print('<h2 class="LC_hcell">Step 1</h2>');
1.452     bisitz   6463:     $r->print('<div>');
1.523     raeburn  6464:     $r->print(&Apache::lonhtmlcommon::start_pick_box(undef,'parmlevel'));
1.211     www      6465:     &levelmenu($r,\%alllevs,$parmlev);
1.610     raeburn  6466:     $r->print(&Apache::lonhtmlcommon::row_closure());
                   6467:     &mapmenu($r,\%allmaps,$pschp,\%maptitles,\%symbp,$parmlev);
1.447     bisitz   6468:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.445     neumanie 6469:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   6470:     $r->print('</div></div>');
1.446     bisitz   6471: 
1.456     bisitz   6472:     $r->print('<div class="LC_Box">');
1.452     bisitz   6473:     $r->print('<div>');
1.581     raeburn  6474:     &displaymenu($r,\%allparms,\@pscat,\%keyorder);
1.453     schualex 6475:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.446     bisitz   6476:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parts to View')));
1.553     raeburn  6477:     my $sectionselector = &sectionmenu(\@selected_sections);
                   6478:     my $groupselector = &groupmenu(\@selected_groups);
1.481     amueller 6479:     $r->print('<table>'.
1.553     raeburn  6480:               '<tr><th>'.&mt('Parts').'</th>');
                   6481:     if ($sectionselector) {
                   6482:         $r->print('<th>'.&mt('Section(s)').'</th>');
                   6483:     }
                   6484:     if ($groupselector) {
                   6485:         $r->print('<th>'.&mt('Group(s)').'</th>');
                   6486:     }
                   6487:     $r->print('</tr><tr><td>');
1.211     www      6488:     &partmenu($r,\%allparts,\@psprt);
1.553     raeburn  6489:     $r->print('</td>');
                   6490:     if ($sectionselector) { 
                   6491:         $r->print('<td>'.$sectionselector.'</td>');
                   6492:     }
                   6493:     if ($groupselector) {
                   6494:         $r->print('<td>'.$groupselector.'</td>');
                   6495:     }
                   6496:     $r->print('</tr></table>');
1.447     bisitz   6497:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.445     neumanie 6498:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   6499:     $r->print('</div></div>');
                   6500: 
1.456     bisitz   6501:     $r->print('<div class="LC_Box">');
1.452     bisitz   6502:     $r->print('<div>');
1.214     www      6503:     my $sortorder=$env{'form.sortorder'};
                   6504:     unless ($sortorder) { $sortorder='realmstudent'; }
1.612     raeburn  6505:     &sortmenu($r,$sortorder,'newoverview');
1.445     neumanie 6506:     $r->print('</div></div>');
1.446     bisitz   6507: 
1.624   ! raeburn  6508:     $r->print('<p><input type="submit" name="dis" value="'.&mt('Display').'" id="newoverviewdis" /></p>');
1.446     bisitz   6509: 
1.211     www      6510: # Build the list data hash from the specified parms
                   6511: 
                   6512:     my $listdata;
                   6513:     %{$listdata}=();
                   6514: 
                   6515:     foreach my $cat (@pscat) {
1.269     raeburn  6516:         &secgroup_lister($cat,$pschp,$parmlev,$listdata,\@psprt,\@selected_sections,\%defkeytype,\%allmaps,\@ids,\%symbp);
                   6517:         &secgroup_lister($cat,$pschp,$parmlev,$listdata,\@psprt,\@selected_groups,\%defkeytype,\%allmaps,\@ids,\%symbp);
1.211     www      6518:     }
                   6519: 
1.624   ! raeburn  6520:     my $foundkeys;
        !          6521:     if ($env{'form.newoverviewsubm'}) {
1.211     www      6522: 
1.624   ! raeburn  6523:         if ($env{'form.newoverviewsubm'} eq 'store') { &storedata($r,$crs,$dom); }
1.211     www      6524: 
                   6525: # Read modified data
                   6526: 
1.481     amueller 6527:         my $resourcedata=&readdata($crs,$dom);
1.211     www      6528: 
                   6529: # List data
                   6530: 
1.608     raeburn  6531:         my $hash_for_realm;
                   6532:         if (($parmlev eq 'map') && (keys(%allmaps))) {
                   6533:             %{$hash_for_realm} = reverse(%allmaps);
                   6534:         } elsif (($parmlev eq 'full') && (keys(%symbp))) {
                   6535:             for (my $i=0; $i<@ids; $i++) {
                   6536:                 $hash_for_realm->{$symbp{$ids[$i]}} = $i;
                   6537:             }
                   6538:         }
1.624   ! raeburn  6539:         $foundkeys = &listdata($r,$resourcedata,$listdata,$sortorder,'newoverview',undef,$readonly,$parmlev,$hash_for_realm,$pschp);
1.568     raeburn  6540:     }
                   6541:     $r->print(&tableend());
1.624   ! raeburn  6542:     if ((!$readonly) && ($foundkeys)) {
        !          6543:         $r->print( ($env{'form.newoverviewsubm'}? '<p><input type="submit" name="store" id="newoverviewstore" value="'.&mt('Save').'" /></p>':'') );
1.211     www      6544:     }
1.568     raeburn  6545:     $r->print('</form>');
1.624   ! raeburn  6546:     if ($env{'form.newoverviewsubm'}) {
        !          6547:         $r->print(<<"END");
        !          6548: <script type="text/javascript">
        !          6549: const form = document.getElementById('newoverviewform');
        !          6550: const storebutton = document.getElementById('newoverviewstore');
        !          6551: const disbutton = document.getElementById('newoverviewdis');
        !          6552: const submethod = document.getElementById('newoverviewsubm');
        !          6553: if (storebutton) { 
        !          6554:   storebutton.addEventListener('keydown', (e) => {
        !          6555:     if (e.key === 'Enter') {
        !          6556:       if (validateParms()) {
        !          6557:         if (form) {
        !          6558:           if (submethod) {
        !          6559:             submethod.value='store';
        !          6560:           }
        !          6561:           form.submit();
        !          6562:         }
        !          6563:       }
        !          6564:       e.preventDefault();
        !          6565:       return;
        !          6566:     }
        !          6567:   });
        !          6568:   storebutton.addEventListener('click', (e) => {
        !          6569:     if (validateParms()) {
        !          6570:       if (form) {
        !          6571:         if (submethod) {
        !          6572:           submethod.value='store';
        !          6573:         }
        !          6574:         form.submit();
        !          6575:       }
        !          6576:     }
        !          6577:     e.preventDefault();
        !          6578:     return;
        !          6579:   });
        !          6580: }
        !          6581: if (disbutton) {
        !          6582:   disbutton.addEventListener('keydown', (e) => {
        !          6583:     if (e.key === 'Enter') {
        !          6584:       if (form) {
        !          6585:         if (submethod) {
        !          6586:           submethod.value='dis';
        !          6587:         }
        !          6588:         form.submit();
        !          6589:       }
        !          6590:       e.preventDefault();
        !          6591:     }
        !          6592:   });
        !          6593:   disbutton.addEventListener('click', (e) => {
        !          6594:     if (form) {
        !          6595:       if (submethod) {
        !          6596:         submethod.value='dis';
        !          6597:       }
        !          6598:       form.submit();
        !          6599:       return;
        !          6600:     }
        !          6601:     e.preventDefault();
        !          6602:   });
        !          6603: }
        !          6604: 
        !          6605: </script>
        !          6606: 
        !          6607: END
        !          6608:     }
1.507     www      6609:     &endSettingsScreen($r);
                   6610:     $r->print(&Apache::loncommon::end_page());
1.208     www      6611: }
                   6612: 
1.563     damieng  6613: # Fills $listdata with parameter information.
                   6614: # Keys use the format course id.[section id].part.name and course id.[section id].part.name.type.
                   6615: # The non-type value is always 1.
                   6616: #
                   6617: # @param {string} $cat - parameter name
1.566     damieng  6618: # @param {string} $pschp - selected map pc, or 'all'
1.563     damieng  6619: # @param {string} $parmlev - selected level value (full|map|general), or ''
                   6620: # @param {hash reference} $listdata - the parameter data that will be modified
                   6621: # @param {array reference} $psprt - selected parts
                   6622: # @param {array reference} $selections - selected sections
                   6623: # @param {hash reference} $defkeytype - hash parameter name -> parameter type
1.566     damieng  6624: # @param {hash reference} $allmaps - hash map pc -> map src
                   6625: # @param {array reference} $ids - resource and map ids
                   6626: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' or resource symb
1.269     raeburn  6627: sub secgroup_lister {
                   6628:     my ($cat,$pschp,$parmlev,$listdata,$psprt,$selections,$defkeytype,$allmaps,$ids,$symbp) = @_;
                   6629:     foreach my $item (@{$selections}) {
                   6630:         foreach my $part (@{$psprt}) {
                   6631:             my $rootparmkey=$env{'request.course.id'};
                   6632:             if (($item ne 'all') && ($item ne 'none') && ($item)) {
                   6633:                 $rootparmkey.='.['.$item.']';
                   6634:             }
                   6635:             if ($parmlev eq 'general') {
                   6636: # course-level parameter
                   6637:                 my $newparmkey=$rootparmkey.'.'.$part.'.'.$cat;
                   6638:                 $$listdata{$newparmkey}=1;
                   6639:                 $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6640:             } elsif ($parmlev eq 'map') {
                   6641: # map-level parameter
1.548     raeburn  6642:                 foreach my $mapid (keys(%{$allmaps})) {
1.269     raeburn  6643:                     if (($pschp ne 'all') && ($pschp ne $mapid)) { next; }
                   6644:                     my $newparmkey=$rootparmkey.'.'.$$allmaps{$mapid}.'___(all).'.$part.'.'.$cat;
                   6645:                     $$listdata{$newparmkey}=1;
                   6646:                     $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6647:                 }
                   6648:             } else {
                   6649: # resource-level parameter
                   6650:                 foreach my $rid (@{$ids}) {
                   6651:                     my ($map,$resid,$url)=&Apache::lonnet::decode_symb($$symbp{$rid});
                   6652:                     if (($pschp ne 'all') && ($$allmaps{$pschp} ne $map)) { next; }
                   6653:                     my $newparmkey=$rootparmkey.'.'.$$symbp{$rid}.'.'.$part.'.'.$cat;
                   6654:                     $$listdata{$newparmkey}=1;
                   6655:                     $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6656:                 }
                   6657:             }
                   6658:         }
                   6659:     }
                   6660: }
                   6661: 
1.563     damieng  6662: # UI to edit parameter settings starting with a list of all existing parameters.
                   6663: # (called by setoverview action)
                   6664: #
                   6665: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      6666: sub overview {
1.568     raeburn  6667:     my ($r,$parm_permission) = @_;
1.208     www      6668:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6669:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6670:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.568     raeburn  6671:     my $readonly = 1;
                   6672:     if ($parm_permission->{'edit'}) {
                   6673:         undef($readonly);
                   6674:     }
1.549     raeburn  6675:     my $js = '<script type="text/javascript">'."\n".
                   6676:              '// <![CDATA['."\n".
                   6677:              &toggleparmtextbox_js()."\n".
                   6678:              &validateparms_js()."\n".
                   6679:              &ipacc_boxes_js()."\n".
1.622     raeburn  6680:              &grace_js()."\n".
1.558     raeburn  6681:              &done_proctor_js()."\n".
1.588     raeburn  6682:              &deeplink_js()."\n".
1.549     raeburn  6683:              '// ]]>'."\n".
                   6684:              '</script>'."\n";
1.414     droeschl 6685:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview',
1.473     amueller 6686:     text=>"Overview Mode"});
1.549     raeburn  6687:     my %loaditems = (
                   6688:                       'onload'   => "showHideLenient();",
                   6689:                     );
                   6690: 
                   6691:     my $start_page=&Apache::loncommon::start_page('Modify Parameters',$js,{'add_entries' => \%loaditems,});
1.298     albertel 6692:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview');
1.507     www      6693:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6694:     &startSettingsScreen($r,'parmset',$crstype);
1.549     raeburn  6695:     $r->print('<form method="post" action="/adm/parmset?action=setoverview" name="parmform" onsubmit="return validateParms();">');
1.507     www      6696: 
1.208     www      6697: # Store modified
                   6698: 
1.568     raeburn  6699:     unless ($readonly) {
                   6700:         &storedata($r,$crs,$dom);
                   6701:     }
1.208     www      6702: 
                   6703: # Read modified data
                   6704: 
1.552     raeburn  6705:     my ($resourcedata,$classlist)=&readdata($crs,$dom);
1.208     www      6706: 
1.214     www      6707: 
                   6708:     my $sortorder=$env{'form.sortorder'};
                   6709:     unless ($sortorder) { $sortorder='realmstudent'; }
1.608     raeburn  6710:     &sortmenu($r,$sortorder,'overview');
1.214     www      6711: 
1.568     raeburn  6712:     my $submitbutton = '<input type="submit" value="'.&mt('Save').'" />';
                   6713: 
                   6714:     if ($readonly) {
                   6715:         $r->print('<p>'.$submitbutton.'</p>');
                   6716:     }
                   6717: 
1.208     www      6718: # List data
                   6719: 
1.568     raeburn  6720:     my $foundkeys=&listdata($r,$resourcedata,$resourcedata,$sortorder,'overview',$classlist,$readonly);
                   6721:     $r->print(&tableend().'<p>');
                   6722:     if ($foundkeys) {
                   6723:         unless ($readonly) {
                   6724:             $r->print('<p>'.$submitbutton.'</p>');
                   6725:         }
                   6726:     } else {
                   6727:         $r->print('<p class="LC_info">'.&mt('There are no parameters.').'</p>');
                   6728:     }
                   6729:     $r->print('</form>'.&Apache::loncommon::end_page());
1.120     www      6730: }
1.121     www      6731: 
1.560     damieng  6732: # Unused sub.
1.563     damieng  6733: #
                   6734: # @param {Apache2::RequestRec} $r - the Apache request
1.333     albertel 6735: sub clean_parameters {
                   6736:     my ($r) = @_;
                   6737:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6738:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
                   6739: 
1.414     droeschl 6740:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=cleanparameters',
1.473     amueller 6741:         text=>"Clean Parameters"});
1.333     albertel 6742:     my $start_page=&Apache::loncommon::start_page('Clean Parameters');
                   6743:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Clean');
                   6744:     $r->print(<<ENDOVER);
                   6745: $start_page
                   6746: $breadcrumbs
                   6747: <form method="post" action="/adm/parmset?action=cleanparameters" name="parmform">
                   6748: ENDOVER
                   6749: # Store modified
                   6750: 
                   6751:     &storedata($r,$crs,$dom);
                   6752: 
                   6753: # Read modified data
                   6754: 
                   6755:     my $resourcedata=&readdata($crs,$dom);
                   6756: 
                   6757: # List data
                   6758: 
                   6759:     $r->print('<h3>'.
1.473     amueller 6760:           &mt('These parameters refer to resources that do not exist.').
                   6761:           '</h3>'.
                   6762:           '<input type="submit" value="'.&mt('Delete Selected').'" />'.'<br />'.
                   6763:           '<br />');
1.333     albertel 6764:     $r->print(&Apache::loncommon::start_data_table().
1.473     amueller 6765:           '<tr>'.
                   6766:           '<th>'.&mt('Delete').'</th>'.
                   6767:           '<th>'.&mt('Parameter').'</th>'.
                   6768:           '</tr>');
1.333     albertel 6769:     foreach my $thiskey (sort(keys(%{$resourcedata}))) {
1.560     damieng  6770:         next if (!exists($resourcedata->{$thiskey.'.type'})
                   6771:             && $thiskey=~/\.type$/);
                   6772:         my %data = &parse_key($thiskey);
                   6773:         if (1) { #exists($data{'realm_exists'})
                   6774:             #&& !$data{'realm_exists'}) {
                   6775:             $r->print(&Apache::loncommon::start_data_table_row().
                   6776:                 '<tr>'.
                   6777:                 '<td><input type="checkbox" name="del_'.$thiskey.'" /></td>'              );
                   6778: 
                   6779:             $r->print('<td>');
                   6780:             my $display_value = $resourcedata->{$thiskey};
                   6781:             if (&isdateparm($resourcedata->{$thiskey.'.type'})) {
                   6782:             $display_value =
                   6783:                 &Apache::lonlocal::locallocaltime($display_value);
                   6784:             }
1.470     raeburn  6785:             my $parmitem = &standard_parameter_names($data{'parameter_name'});
                   6786:             $parmitem = &mt($parmitem);
1.560     damieng  6787:             $r->print(&mt('Parameter: "[_1]" with value: "[_2]"',
                   6788:                 $parmitem,$resourcedata->{$thiskey}));
                   6789:             $r->print('<br />');
                   6790:             if ($data{'scope_type'} eq 'all') {
                   6791:                 $r->print(&mt('All users'));
                   6792:             } elsif ($data{'scope_type'} eq 'user') {
                   6793:                 $r->print(&mt('User: [_1]',join(':',@{$data{'scope'}})));
1.581     raeburn  6794:             } elsif ($data{'scope_type'} eq 'secgroup') {
                   6795:                 $r->print(&mt('Group/Section: [_1]',$data{'scope'}));
1.560     damieng  6796:             }
                   6797:             $r->print('<br />');
                   6798:             if ($data{'realm_type'} eq 'all') {
                   6799:                 $r->print(&mt('All Resources'));
                   6800:             } elsif ($data{'realm_type'} eq 'folder') {
                   6801:                 $r->print(&mt('Folder: [_1]'),$data{'realm'});
                   6802:             } elsif ($data{'realm_type'} eq 'symb') {
                   6803:             my ($map,$resid,$url) =
                   6804:                 &Apache::lonnet::decode_symb($data{'realm'});
                   6805:             $r->print(&mt('Resource: [_1]with ID: [_2]in folder [_3]',
                   6806:                         $url.' <br />&nbsp;&nbsp;&nbsp;',
                   6807:                         $resid.' <br />&nbsp;&nbsp;&nbsp;',$map));
                   6808:             }
                   6809:             $r->print(' <br />&nbsp;&nbsp;&nbsp;'.&mt('Part: [_1]',$data{'parameter_part'}));
                   6810:             $r->print('</td></tr>');
                   6811: 
1.473     amueller 6812:         }
1.333     albertel 6813:     }
                   6814:     $r->print(&Apache::loncommon::end_data_table().'<p>'.
1.473     amueller 6815:           '<input type="submit" value="'.&mt('Delete Selected').'" />'.
1.507     www      6816:           '</p></form>');
                   6817:     &endSettingsScreen($r);
                   6818:     $r->print(&Apache::loncommon::end_page());
1.333     albertel 6819: }
                   6820: 
1.563     damieng  6821: # UI to shift all dates (called by dateshift1 action).
                   6822: # Used by overview mode.
                   6823: #
                   6824: # @param {Apache2::RequestRec} $r - the Apache request
1.390     www      6825: sub date_shift_one {
                   6826:     my ($r) = @_;
                   6827:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6828:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6829:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.594     raeburn  6830:     my $sec = $env{'request.course.sec'};
1.414     droeschl 6831:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'},
1.473     amueller 6832:         text=>"Shifting Dates"});
1.594     raeburn  6833:     my $submit_text = &mt('Shift all dates accordingly');
                   6834:     if ($sec ne '') {
1.595     raeburn  6835:         my @groups;
                   6836:         if ($env{'request.course.groups'} ne '') {
                   6837:             @groups = split(/:/,$env{'request.course.groups'});
                   6838:         }
                   6839:         if (@groups) {
                   6840:             $submit_text = &mt("Shift dates set just for your section/group(s), accordingly");
                   6841:         } else {
                   6842:             $submit_text = &mt("Shift dates set just for your section, accordingly");
                   6843:         }
1.594     raeburn  6844:     }
1.390     www      6845:     my $start_page=&Apache::loncommon::start_page('Shift Dates');
                   6846:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
1.507     www      6847:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6848:     &startSettingsScreen($r,'parmset',$crstype);
1.538     bisitz   6849:     $r->print('<form name="shiftform" method="post" action="">'.
1.390     www      6850:               '<table><tr><td>'.&mt('Currently set date:').'</td><td>'.
                   6851:               &Apache::lonlocal::locallocaltime($env{'form.timebase'}).'</td></tr>'.
                   6852:               '<tr><td>'.&mt('Shifted date:').'</td><td>'.
1.541     bisitz   6853:                     &Apache::lonhtmlcommon::date_setter('shiftform',
1.390     www      6854:                                                         'timeshifted',
                   6855:                                                         $env{'form.timebase'},,
                   6856:                                                         '').
                   6857:               '</td></tr></table>'.
                   6858:               '<input type="hidden" name="action" value="dateshift2" />'.
                   6859:               '<input type="hidden" name="timebase" value="'.$env{'form.timebase'}.'" />'.
1.594     raeburn  6860:               '<input type="submit" value="'.$submit_text.'" /></form>');
1.507     www      6861:     &endSettingsScreen($r);
1.390     www      6862:     $r->print(&Apache::loncommon::end_page());
                   6863: }
                   6864: 
1.563     damieng  6865: # UI to shift all dates (second form).
                   6866: #
                   6867: # @param {Apache2::RequestRec} $r - the Apache request
1.390     www      6868: sub date_shift_two {
                   6869:     my ($r) = @_;
                   6870:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6871:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.594     raeburn  6872:     my $sec = $env{'request.course.sec'};
1.531     raeburn  6873:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.414     droeschl 6874:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'},
1.473     amueller 6875:         text=>"Shifting Dates"});
1.390     www      6876:     my $start_page=&Apache::loncommon::start_page('Shift Dates');
                   6877:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
1.507     www      6878:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6879:     &startSettingsScreen($r,'parmset',$crstype);
1.390     www      6880:     my $timeshifted=&Apache::lonhtmlcommon::get_date_from_form('timeshifted');
1.594     raeburn  6881:     $r->print('<h2>'.&mt('Shift Dates').'</h2>');
                   6882:     if ($sec ne '') {
1.595     raeburn  6883:         my @groups;
                   6884:         if ($env{'request.course.groups'} ne '') {
                   6885:             @groups = split(/:/,$env{'request.course.groups'});
                   6886:         }
                   6887:         if (@groups) {
                   6888:             $r->print('<p>'.
                   6889:                       &mt("Shift dates set just for your section/group(s), such that [_1] becomes [_2]",
                   6890:                           &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6891:                           &Apache::lonlocal::locallocaltime($timeshifted)).
                   6892:                       '</p>');
                   6893:         } else {
                   6894:             $r->print('<p>'.
                   6895:                       &mt("Shift dates set just for your section, such that [_1] becomes [_2]",
                   6896:                           &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6897:                           &Apache::lonlocal::locallocaltime($timeshifted)).
                   6898:                       '</p>');
                   6899:         }
1.594     raeburn  6900:     } else {
                   6901:         $r->print('<p>'.&mt('Shifting all dates such that [_1] becomes [_2]',
                   6902:                             &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6903:                             &Apache::lonlocal::locallocaltime($timeshifted)).
                   6904:                   '</p>');
                   6905:     }
1.390     www      6906:     my $delta=$timeshifted-$env{'form.timebase'};
1.594     raeburn  6907:     my $numchanges = 0;
                   6908:     my $result = &dateshift($delta,\$numchanges);
                   6909:     if ($result eq 'ok') {
                   6910:         $r->print(
                   6911:             &Apache::lonhtmlcommon::confirm_success(&mt('Completed shifting of [quant,_1,date setting]',
                   6912:                                                     $numchanges)));
                   6913:     } elsif ($result eq 'con_delayed') {
                   6914:         $r->print(
                   6915:             &Apache::lonhtmlcommon::confirm_success(&mt('Queued shifting of [quant,_1,date setting]',
                   6916:                                                         $numchanges)));
                   6917:     } else {
                   6918:         $r->print(
                   6919:             &Apache::lonhtmlcommon::confirm_success(&mt('An error occurred attempting to shift dates'),1));
                   6920:     }
1.543     bisitz   6921:     $r->print(
                   6922:         '<br /><br />'.
                   6923:         &Apache::lonhtmlcommon::actionbox(
                   6924:             ['<a href="/adm/parmset">'.&mt('Content and Problem Settings').'</a>']));
1.507     www      6925:     &endSettingsScreen($r);
1.390     www      6926:     $r->print(&Apache::loncommon::end_page());
                   6927: }
                   6928: 
1.563     damieng  6929: # Returns the different components of a resourcedata key.
                   6930: # Keys: scope_type, scope, realm_type, realm, realm_title,
                   6931: #       realm_exists, parameter_part, parameter_name.
                   6932: # Was used by clean_parameters (which is unused).
                   6933: #
                   6934: # @param {string} $key - the parameter key
                   6935: # @returns {hash}
1.333     albertel 6936: sub parse_key {
                   6937:     my ($key) = @_;
                   6938:     my %data;
                   6939:     my ($middle,$part,$name)=
1.572     damieng  6940:     ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.333     albertel 6941:     $data{'scope_type'} = 'all';
                   6942:     if ($middle=~/^\[(.*)\]/) {
1.560     damieng  6943:         $data{'scope'} = $1;
                   6944:         if ($data{'scope'}=~/^useropt\:($match_username)\:($match_domain)/) {
                   6945:             $data{'scope_type'} = 'user';
                   6946:             $data{'scope'} = [$1,$2];
                   6947:         } else {
1.581     raeburn  6948:             $data{'scope_type'} = 'secgroup';
1.560     damieng  6949:         }
                   6950:         $middle=~s/^\[(.*)\]//;
1.333     albertel 6951:     }
                   6952:     $middle=~s/\.+$//;
                   6953:     $middle=~s/^\.+//;
                   6954:     $data{'realm_type'}='all';
                   6955:     if ($middle=~/^(.+)\_\_\_\(all\)$/) {
1.560     damieng  6956:         $data{'realm'} = $1;
                   6957:         $data{'realm_type'} = 'folder';
                   6958:         $data{'realm_title'} = &Apache::lonnet::gettitle($data{'realm'});
                   6959:         ($data{'realm_exists'}) = &Apache::lonnet::is_on_map($data{'realm'});
1.333     albertel 6960:     } elsif ($middle) {
1.560     damieng  6961:         $data{'realm'} = $middle;
                   6962:         $data{'realm_type'} = 'symb';
                   6963:         $data{'realm_title'} = &Apache::lonnet::gettitle($data{'realm'});
                   6964:         my ($map,$resid,$url) = &Apache::lonnet::decode_symb($data{'realm'});
                   6965:         $data{'realm_exists'} = &Apache::lonnet::symbverify($data{'realm'},$url);
1.333     albertel 6966:     }
1.446     bisitz   6967: 
1.333     albertel 6968:     $data{'parameter_part'} = $part;
                   6969:     $data{'parameter_name'} = $name;
                   6970: 
                   6971:     return %data;
                   6972: }
                   6973: 
1.239     raeburn  6974: 
1.563     damieng  6975: # Calls loncommon::start_page with the "Settings" title.
1.416     jms      6976: sub header {
1.507     www      6977:     return &Apache::loncommon::start_page('Settings');
1.416     jms      6978: }
1.193     albertel 6979: 
                   6980: 
                   6981: 
1.560     damieng  6982: ##################################################
                   6983: # MAIN MENU
                   6984: ##################################################
                   6985: 
1.563     damieng  6986: # Content and problem settings main menu.
                   6987: #
                   6988: # @param {Apache2::RequestRec} $r - the Apache request
                   6989: # @param {boolean} $parm_permission - true if the user has permission to edit the current course or section
1.193     albertel 6990: sub print_main_menu {
                   6991:     my ($r,$parm_permission)=@_;
                   6992:     #
1.414     droeschl 6993:     $r->print(&header());
1.507     www      6994:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Content and Problem Settings'));
1.531     raeburn  6995:     my $crstype = &Apache::loncommon::course_type();
                   6996:     my $lc_crstype = lc($crstype);
                   6997: 
                   6998:     &startSettingsScreen($r,'parmset',$crstype);
1.193     albertel 6999:     $r->print(<<ENDMAINFORMHEAD);
                   7000: <form method="post" enctype="multipart/form-data"
                   7001:       action="/adm/parmset" name="studentform">
                   7002: ENDMAINFORMHEAD
                   7003: #
1.195     albertel 7004:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   7005:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
1.268     albertel 7006:     my $vgr  = &Apache::lonnet::allowed('vgr',$env{'request.course.id'});
1.366     albertel 7007:     my $mgr  = &Apache::lonnet::allowed('mgr',$env{'request.course.id'});
1.520     raeburn  7008:     my $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'});
1.568     raeburn  7009:     my $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'});
                   7010:     my $vpa = &Apache::lonnet::allowed('vpa',$env{'request.course.id'});
1.520     raeburn  7011:     if ((!$dcm) && ($env{'request.course.sec'} ne '')) {
                   7012:         $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'}.
                   7013:                                         '/'.$env{'request.course.sec'});
                   7014:     }
1.568     raeburn  7015:     if ((!$vcb) && ($env{'request.course.sec'} ne '')) {
                   7016:         $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'}.
                   7017:                                         '/'.$env{'request.course.sec'});
                   7018:     }
                   7019:     my (%linktext,%linktitle,%url);
                   7020:     if ($parm_permission->{'edit'}) {
                   7021:         %linktext = (
                   7022:                      newoverview     => 'Edit Resource Parameters - Overview Mode',
                   7023:                      settable        => 'Edit Resource Parameters - Table Mode',
                   7024:                      setoverview     => 'Modify Resource Parameters - Overview Mode',
                   7025:                     );
                   7026:         %linktitle = (
                   7027:                      newoverview     => 'Set/Modify resource parameters in overview mode.',
                   7028:                      settable        => 'Set/Modify resource parameters in table mode.',
                   7029:                      setoverview     => 'Set/Modify existing resource parameters in overview mode.',
                   7030:                      );
                   7031:     } else {
                   7032:         %linktext = (
                   7033:                      newoverview     => 'View Resource Parameters - Overview Mode',
                   7034:                      settable        => 'View Resource Parameters - Table Mode',
                   7035:                      setoverview     => 'View Resource Parameters - Overview Mode',
                   7036:                    );
                   7037:         %linktitle = (
                   7038:                      newoverview     => 'Display resource parameters in overview mode.',
                   7039:                      settable        => 'Display resource parameters in table mode.',
                   7040:                      setoverview     => 'Display existing resource parameters in overview mode.',
                   7041:                      );
                   7042:     }
                   7043:     if ($mgr) {
                   7044:         $linktext{'resettimes'} = 'Reset Student Access Times';
                   7045:         $linktitle{'resettimes'} = "Reset access times for folders/maps, resources or the $lc_crstype.";
                   7046:         $url{'resettimes'} = '/adm/helper/resettimes.helper';
                   7047:     } elsif ($vgr) {
                   7048:         $linktext{'resettimes'} = 'Display Student Access Times',
                   7049:         $linktitle{'resettimes'} = "Display access times for folders/maps, resources or the $lc_crstype.",
                   7050:         $url{'resettimes'} = '/adm/accesstimes';
                   7051:     }
1.193     albertel 7052:     my @menu =
1.507     www      7053:         ( { categorytitle=>"Content Settings for this $crstype",
1.473     amueller 7054:         items => [
                   7055:           { linktext => 'Portfolio Metadata',
                   7056:             url => '/adm/parmset?action=setrestrictmeta',
1.568     raeburn  7057:             permission => $parm_permission->{'setrestrictmeta'},
1.477     raeburn  7058:             linktitle => "Restrict metadata for this $lc_crstype." ,
1.473     amueller 7059:             icon =>'contact-new.png'   ,
                   7060:             },
1.568     raeburn  7061:           { linktext => $linktext{'resettimes'},
                   7062:             url => $url{'resettimes'},
                   7063:             permission => ($vgr || $mgr),
                   7064:             linktitle => $linktitle{'resettimes'},
                   7065:             icon => 'start-here.png',
1.473     amueller 7066:             },
1.520     raeburn  7067:           { linktext => 'Blocking Communication/Resource Access',
                   7068:             url => '/adm/setblock',
1.568     raeburn  7069:             permission => ($vcb || $dcm),
1.520     raeburn  7070:             linktitle => 'Configure blocking of communication/collaboration and access to resources during an exam',
                   7071:             icon => 'comblock.png',
                   7072:             },
1.473     amueller 7073:           { linktext => 'Set Parameter Setting Default Actions',
                   7074:             url => '/adm/parmset?action=setdefaults',
1.568     raeburn  7075:             permission => $parm_permission->{'setdefaults'},
1.473     amueller 7076:             linktitle =>'Set default actions for parameters.'  ,
                   7077:             icon => 'folder-new.png'  ,
                   7078:             }]},
                   7079:       { categorytitle => 'New and Existing Parameter Settings for Resources',
                   7080:         items => [
                   7081:           { linktext => 'Edit Resource Parameters - Helper Mode',
                   7082:             url => '/adm/helper/parameter.helper',
1.568     raeburn  7083:             permission => $parm_permission->{'helper'},
1.473     amueller 7084:             linktitle =>'Set/Modify resource parameters in helper mode.'  ,
                   7085:             icon => 'dialog-information.png'  ,
                   7086:             #help => 'Parameter_Helper',
                   7087:             },
1.568     raeburn  7088:           { linktext => $linktext{'newoverview'},
1.473     amueller 7089:             url => '/adm/parmset?action=newoverview',
1.568     raeburn  7090:             permission => $parm_permission->{'newoverview'},
                   7091:             linktitle => $linktitle{'newoverview'},
                   7092:             icon => 'edit-find.png',
1.473     amueller 7093:             #help => 'Parameter_Overview',
                   7094:             },
1.568     raeburn  7095:           { linktext => $linktext{'settable'},
1.473     amueller 7096:             url => '/adm/parmset?action=settable',
1.568     raeburn  7097:             permission => $parm_permission->{'settable'},
                   7098:             linktitle => $linktitle{'settable'},
                   7099:             icon => 'edit-copy.png',
1.473     amueller 7100:             #help => 'Table_Mode',
                   7101:             }]},
1.417     droeschl 7102:            { categorytitle => 'Existing Parameter Settings for Resources',
1.473     amueller 7103:          items => [
1.570     raeburn  7104:           { linktext => $linktext{'setoverview'},
1.473     amueller 7105:             url => '/adm/parmset?action=setoverview',
1.568     raeburn  7106:             permission => $parm_permission->{'setoverview'},
                   7107:             linktitle => $linktitle{'setoverview'},
                   7108:             icon => 'preferences-desktop-wallpaper.png',
1.473     amueller 7109:             #help => 'Parameter_Overview',
                   7110:             },
                   7111:           { linktext => 'Change Log',
                   7112:             url => '/adm/parmset?action=parameterchangelog',
1.568     raeburn  7113:             permission => $parm_permission->{'parameterchangelog'},
1.477     raeburn  7114:             linktitle =>"View parameter and $lc_crstype blog posting/user notification change log."  ,
1.487     wenzelju 7115:             icon => 'document-properties.png',
1.473     amueller 7116:             }]}
1.193     albertel 7117:           );
1.414     droeschl 7118:     $r->print(&Apache::lonhtmlcommon::generate_menu(@menu));
1.539     raeburn  7119:     $r->print('</form>');
1.507     www      7120:     &endSettingsScreen($r);
1.539     raeburn  7121:     $r->print(&Apache::loncommon::end_page());
1.193     albertel 7122:     return;
                   7123: }
1.414     droeschl 7124: 
1.416     jms      7125: 
                   7126: 
1.560     damieng  7127: ##################################################
                   7128: # PORTFOLIO METADATA
                   7129: ##################################################
                   7130: 
1.563     damieng  7131: # Prints HTML to edit an item of portfolio metadata. The HTML contains several td elements (no tr).
                   7132: # It looks like field titles are not localized.
                   7133: #
                   7134: # @param {Apache2::RequestRec} $r - the Apache request
                   7135: # @param {string} $field_name - metadata field name
                   7136: # @param {string} $field_text - metadata field title, in English unless manually added
                   7137: # @param {boolean} $added_flag - true if the field was manually added
1.252     banghart 7138: sub output_row {
1.347     banghart 7139:     my ($r, $field_name, $field_text, $added_flag) = @_;
1.252     banghart 7140:     my $output;
1.263     banghart 7141:     my $options=$env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.options'};
                   7142:     my $values=$env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.values'};
1.337     banghart 7143:     if (!defined($options)) {
1.254     banghart 7144:         $options = 'active,stuadd';
1.261     banghart 7145:         $values = '';
1.252     banghart 7146:     }
1.337     banghart 7147:     if (!($options =~ /deleted/)) {
                   7148:         my @options= ( ['active', 'Show to student'],
1.418     schafran 7149:                     ['stuadd', 'Provide text area for students to type metadata'],
1.351     banghart 7150:                     ['choices','Provide choices for students to select from']);
1.473     amueller 7151: #           ['onlyone','Student may select only one choice']);
1.337     banghart 7152:         if ($added_flag) {
                   7153:             push @options,['deleted', 'Delete Metadata Field'];
                   7154:         }
1.351     banghart 7155:        $output = &Apache::loncommon::start_data_table_row();
1.451     bisitz   7156:         $output .= '<td><strong>'.$field_text.':</strong></td>';
1.351     banghart 7157:         $output .= &Apache::loncommon::end_data_table_row();
1.337     banghart 7158:         foreach my $opt (@options) {
1.560     damieng  7159:             my $checked = ($options =~ m/$opt->[0]/) ? ' checked="checked" ' : '' ;
                   7160:             $output .= &Apache::loncommon::continue_data_table_row();
                   7161:             $output .= '<td>'.('&nbsp;' x 5).'<label>
                   7162:                     <input type="checkbox" name="'.
                   7163:                     $field_name.'_'.$opt->[0].'" value="yes"'.$checked.' />'.
                   7164:                     &mt($opt->[1]).'</label></td>';
                   7165:             $output .= &Apache::loncommon::end_data_table_row();
                   7166:         }
1.351     banghart 7167:         $output .= &Apache::loncommon::continue_data_table_row();
1.451     bisitz   7168:         $output .= '<td>'.('&nbsp;' x 10).'<input name="'.$field_name.'_values" type="text" value="'.$values.'" size="80" /></td>';
1.351     banghart 7169:         $output .= &Apache::loncommon::end_data_table_row();
                   7170:         my $multiple_checked;
                   7171:         my $single_checked;
                   7172:         if ($options =~ m/onlyone/) {
1.422     bisitz   7173:             $multiple_checked = '';
1.423     bisitz   7174:             $single_checked = ' checked="checked"';
1.351     banghart 7175:         } else {
1.423     bisitz   7176:             $multiple_checked = ' checked="checked"';
1.422     bisitz   7177:             $single_checked = '';
1.351     banghart 7178:         }
1.560     damieng  7179:         $output .= &Apache::loncommon::continue_data_table_row();
                   7180:         $output .= '<td>'.('&nbsp;' x 10).'
                   7181:                     <input type="radio" name="'.$field_name.'_onlyone" value="multiple"'.$multiple_checked .' />
                   7182:                     '.&mt('Student may select multiple choices from list').'</td>';
                   7183:         $output .= &Apache::loncommon::end_data_table_row();
                   7184:         $output .= &Apache::loncommon::continue_data_table_row();
                   7185:         $output .= '<td>'.('&nbsp;' x 10).'
                   7186:                     <input type="radio" name="'.$field_name.'_onlyone"  value="single"'.$single_checked.' />
                   7187:                     '.&mt('Student may select only one choice from list').'</td>';
                   7188:         $output .= &Apache::loncommon::end_data_table_row();
1.252     banghart 7189:     }
                   7190:     return ($output);
                   7191: }
1.416     jms      7192: 
                   7193: 
1.560     damieng  7194: # UI to order portfolio metadata fields.
1.563     damieng  7195: # Currently useless because addmetafield does not work.
                   7196: #
                   7197: # @param {Apache2::RequestRec} $r - the Apache request
1.340     banghart 7198: sub order_meta_fields {
                   7199:     my ($r)=@_;
                   7200:     my $idx = 1;
                   7201:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7202:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7203:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};;
1.341     banghart 7204:     $r->print(&Apache::loncommon::start_page('Order Metadata Fields'));
1.560     damieng  7205:     &Apache::lonhtmlcommon::add_breadcrumb(
                   7206:         {href=>'/adm/parmset?action=addmetadata',
1.473     amueller 7207:         text=>"Add Metadata Field"});
1.560     damieng  7208:     &Apache::lonhtmlcommon::add_breadcrumb(
                   7209:         {href=>"/adm/parmset?action=setrestrictmeta",
                   7210:         text=>"Restrict Metadata"},
                   7211:         {text=>"Order Metadata"});
1.345     banghart 7212:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Order Metadata'));
1.531     raeburn  7213:     &startSettingsScreen($r,'parmset',$crstype);
1.340     banghart 7214:     if ($env{'form.storeorder'}) {
                   7215:         my $newpos = $env{'form.newpos'} - 1;
                   7216:         my $currentpos = $env{'form.currentpos'} - 1;
                   7217:         my @neworder = ();
1.548     raeburn  7218:         my @oldorder = split(/,/,$env{'course.'.$env{'request.course.id'}.'.metadata.addedorder'});
1.340     banghart 7219:         my $i;
1.341     banghart 7220:         if ($newpos > $currentpos) {
1.340     banghart 7221:         # moving stuff up
                   7222:             for ($i=0;$i<$currentpos;$i++) {
1.560     damieng  7223:                 $neworder[$i]=$oldorder[$i];
1.340     banghart 7224:             }
                   7225:             for ($i=$currentpos;$i<$newpos;$i++) {
1.560     damieng  7226:                 $neworder[$i]=$oldorder[$i+1];
1.340     banghart 7227:             }
                   7228:             $neworder[$newpos]=$oldorder[$currentpos];
                   7229:             for ($i=$newpos+1;$i<=$#oldorder;$i++) {
1.560     damieng  7230:                 $neworder[$i]=$oldorder[$i];
1.340     banghart 7231:             }
                   7232:         } else {
                   7233:         # moving stuff down
1.473     amueller 7234:             for ($i=0;$i<$newpos;$i++) {
                   7235:                 $neworder[$i]=$oldorder[$i];
                   7236:             }
                   7237:             $neworder[$newpos]=$oldorder[$currentpos];
                   7238:             for ($i=$newpos+1;$i<$currentpos+1;$i++) {
                   7239:                 $neworder[$i]=$oldorder[$i-1];
                   7240:             }
                   7241:             for ($i=$currentpos+1;$i<=$#oldorder;$i++) {
                   7242:                 $neworder[$i]=$oldorder[$i];
                   7243:             }
1.340     banghart 7244:         }
1.560     damieng  7245:         my $ordered_fields = join ",", @neworder;
1.343     banghart 7246:         my $put_result = &Apache::lonnet::put('environment',
1.560     damieng  7247:                         {'metadata.addedorder'=>$ordered_fields},$dom,$crs);
                   7248:         &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.metadata.addedorder' => $ordered_fields});
1.340     banghart 7249:     }
1.357     raeburn  7250:     my $fields = &get_added_meta_fieldnames($env{'request.course.id'});
1.341     banghart 7251:     my $ordered_fields;
1.548     raeburn  7252:     my @fields_in_order = split(/,/,$env{'course.'.$env{'request.course.id'}.'.metadata.addedorder'});
1.340     banghart 7253:     if (!@fields_in_order) {
                   7254:         # no order found, pick sorted order then create metadata.addedorder key.
1.548     raeburn  7255:         foreach my $key (sort(keys(%$fields))) {
1.340     banghart 7256:             push @fields_in_order, $key;
1.341     banghart 7257:             $ordered_fields = join ",", @fields_in_order;
1.340     banghart 7258:         }
1.341     banghart 7259:         my $put_result = &Apache::lonnet::put('environment',
1.446     bisitz   7260:                             {'metadata.addedorder'=>$ordered_fields},$dom,$crs);
                   7261:     }
1.340     banghart 7262:     $r->print('<table>');
                   7263:     my $num_fields = scalar(@fields_in_order);
                   7264:     foreach my $key (@fields_in_order) {
                   7265:         $r->print('<tr><td>');
                   7266:         $r->print('<form method="post" action="">');
1.537     bisitz   7267:         $r->print('<select name="newpos" onchange="this.form.submit()">');
1.340     banghart 7268:         for (my $i = 1;$i le $num_fields;$i ++) {
                   7269:             if ($i eq $idx) {
                   7270:                 $r->print('<option value="'.$i.'"  SELECTED>('.$i.')</option>');
                   7271:             } else {
                   7272:                 $r->print('<option value="'.$i.'">'.$i.'</option>');
                   7273:             }
                   7274:         }
                   7275:         $r->print('</select></td><td>');
                   7276:         $r->print('<input type="hidden" name="currentpos" value="'.$idx.'" />');
                   7277:         $r->print('<input type="hidden" name="storeorder" value="true" />');
                   7278:         $r->print('</form>');
                   7279:         $r->print($$fields{$key}.'</td></tr>');
                   7280:         $idx ++;
                   7281:     }
                   7282:     $r->print('</table>');
1.507     www      7283:     &endSettingsScreen($r);
1.340     banghart 7284:     return 'ok';
                   7285: }
1.416     jms      7286: 
                   7287: 
1.563     damieng  7288: # Returns HTML with a Continue button redirecting to the initial portfolio metadata screen.
                   7289: # @returns {string}
1.359     banghart 7290: sub continue {
                   7291:     my $output;
                   7292:     $output .= '<form action="" method="post">';
                   7293:     $output .= '<input type="hidden" name="action" value="setrestrictmeta" />';
1.586     raeburn  7294:     $output .= '<input type="submit" value="'.&mt('Continue').'" />';
1.359     banghart 7295:     return ($output);
                   7296: }
1.416     jms      7297: 
                   7298: 
1.563     damieng  7299: # UI to add a metadata field.
                   7300: # Currenly does not work because of an HTML error (the field is not visible).
                   7301: #
                   7302: # @param {Apache2::RequestRec} $r - the Apache request
1.334     banghart 7303: sub addmetafield {
                   7304:     my ($r)=@_;
1.414     droeschl 7305:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=addmetadata',
1.473     amueller 7306:         text=>"Add Metadata Field"});
1.334     banghart 7307:     $r->print(&Apache::loncommon::start_page('Add Metadata Field'));
                   7308:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Add Metadata Field'));
1.335     banghart 7309:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7310:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7311:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   7312:     &startSettingsScreen($r,'parmset',$crstype);
1.339     banghart 7313:     if (exists($env{'form.undelete'})) {
1.358     banghart 7314:         my @meta_fields = &Apache::loncommon::get_env_multiple('form.undeletefield');
1.339     banghart 7315:         foreach my $meta_field(@meta_fields) {
                   7316:             my $options = $env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.options'};
                   7317:             $options =~ s/deleted//;
                   7318:             $options =~ s/,,/,/;
                   7319:             my $put_result = &Apache::lonnet::put('environment',
                   7320:                                         {'metadata.'.$meta_field.'.options'=>$options},$dom,$crs);
1.446     bisitz   7321: 
1.586     raeburn  7322:             $r->print(&mt('Undeleted Metadata Field [_1] with result [_2]',
                   7323:                           '<strong>'.$env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.added'}.
                   7324:                           '</strong>',$put_result).
                   7325:                       '<br />');
1.339     banghart 7326:         }
1.359     banghart 7327:         $r->print(&continue());
1.339     banghart 7328:     } elsif (exists($env{'form.fieldname'})) {
1.335     banghart 7329:         my $meta_field = $env{'form.fieldname'};
                   7330:         my $display_field = $env{'form.fieldname'};
                   7331:         $meta_field =~ s/\W/_/g;
1.338     banghart 7332:         $meta_field =~ tr/A-Z/a-z/;
1.335     banghart 7333:         my $put_result = &Apache::lonnet::put('environment',
                   7334:                             {'metadata.'.$meta_field.'.values'=>"",
                   7335:                              'metadata.'.$meta_field.'.added'=>"$display_field",
                   7336:                              'metadata.'.$meta_field.'.options'=>""},$dom,$crs);
1.586     raeburn  7337:         $r->print(&mt('Added new Metadata Field [_1] with result [_2]',
                   7338:                       '<strong>'.$env{'form.fieldname'}.'</strong>',$put_result).
                   7339:                   '<br />');
1.359     banghart 7340:         $r->print(&continue());
1.335     banghart 7341:     } else {
1.357     raeburn  7342:         my $fields = &get_deleted_meta_fieldnames($env{'request.course.id'});
1.339     banghart 7343:         if ($fields) {
1.586     raeburn  7344:             $r->print(&mt('You may undelete previously deleted fields.').
                   7345:                       '<br />'.
                   7346:                       &mt('Check those you wish to undelete and click Undelete.').
                   7347:                       '<br />');
1.339     banghart 7348:             $r->print('<form method="post" action="">');
                   7349:             foreach my $key(keys(%$fields)) {
1.581     raeburn  7350:                 $r->print('<label><input type="checkbox" name="undeletefield" value="'.$key.'" />'.$$fields{$key}.'</label><br /');
1.339     banghart 7351:             }
1.586     raeburn  7352:             $r->print('<input type="submit" name="undelete" value="'.&mt('Undelete').'" />');
1.339     banghart 7353:             $r->print('</form>');
                   7354:         }
1.586     raeburn  7355:         $r->print('<hr />'.
                   7356:                   &mt('[_1]Or[_2] you may enter a new metadata field name.',
                   7357:                       '<strong>','</strong>').
1.581     raeburn  7358:                   '<form method="post" action="/adm/parmset?action=addmetadata">');
1.335     banghart 7359:         $r->print('<input type="text" name="fieldname" /><br />');
1.586     raeburn  7360:         $r->print('<input type="submit" value="'.&mt('Add Metadata Field').'" />');
1.581     raeburn  7361:         $r->print('</form>');
1.334     banghart 7362:     }
1.507     www      7363:     &endSettingsScreen($r);
1.334     banghart 7364: }
1.416     jms      7365: 
                   7366: 
                   7367: 
1.560     damieng  7368: # Display or save portfolio metadata.
1.563     damieng  7369: #
                   7370: # @param {Apache2::RequestRec} $r - the Apache request
1.259     banghart 7371: sub setrestrictmeta {
1.240     banghart 7372:     my ($r)=@_;
1.242     banghart 7373:     my $next_meta;
1.244     banghart 7374:     my $output;
1.245     banghart 7375:     my $item_num;
1.246     banghart 7376:     my $put_result;
1.414     droeschl 7377:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setrestrictmeta',
1.473     amueller 7378:         text=>"Restrict Metadata"});
1.280     albertel 7379:     $r->print(&Apache::loncommon::start_page('Restrict Metadata'));
1.298     albertel 7380:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Restrict Metadata'));
1.240     banghart 7381:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7382:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7383:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   7384:     &startSettingsScreen($r,'parmset',$crstype);
1.259     banghart 7385:     my $key_base = $env{'course.'.$env{'request.course.id'}.'.'};
1.252     banghart 7386:     my $save_field = '';
1.586     raeburn  7387:     my %lt = &Apache::lonlocal::texthash(
                   7388:                                            addm => 'Add Metadata Field',
                   7389:                                            ordm => 'Order Metadata Fields',
                   7390:                                            save => 'Save',
                   7391:                                         );
1.259     banghart 7392:     if ($env{'form.restrictmeta'}) {
1.254     banghart 7393:         foreach my $field (sort(keys(%env))) {
1.252     banghart 7394:             if ($field=~m/^form.(.+)_(.+)$/) {
1.254     banghart 7395:                 my $options;
1.252     banghart 7396:                 my $meta_field = $1;
                   7397:                 my $meta_key = $2;
1.253     banghart 7398:                 if ($save_field ne $meta_field) {
1.252     banghart 7399:                     $save_field = $meta_field;
1.473     amueller 7400:                     if ($env{'form.'.$meta_field.'_stuadd'}) {
                   7401:                         $options.='stuadd,';
                   7402:                     }
                   7403:                     if ($env{'form.'.$meta_field.'_choices'}) {
                   7404:                         $options.='choices,';
                   7405:                     }
                   7406:                     if ($env{'form.'.$meta_field.'_onlyone'} eq 'single') {
                   7407:                         $options.='onlyone,';
                   7408:                     }
                   7409:                     if ($env{'form.'.$meta_field.'_active'}) {
                   7410:                         $options.='active,';
                   7411:                     }
                   7412:                     if ($env{'form.'.$meta_field.'_deleted'}) {
                   7413:                         $options.='deleted,';
                   7414:                     }
1.259     banghart 7415:                     my $name = $save_field;
1.560     damieng  7416:                     $put_result = &Apache::lonnet::put('environment',
                   7417:                         {'metadata.'.$meta_field.'.options'=>$options,
                   7418:                         'metadata.'.$meta_field.'.values'=>$env{'form.'.$meta_field.'_values'},
                   7419:                         },$dom,$crs);
1.252     banghart 7420:                 }
                   7421:             }
                   7422:         }
                   7423:     }
1.296     albertel 7424:     &Apache::lonnet::coursedescription($env{'request.course.id'},
1.473     amueller 7425:                        {'freshen_cache' => 1});
1.335     banghart 7426:     # Get the default metadata fields
1.258     albertel 7427:     my %metadata_fields = &Apache::lonmeta::fieldnames('portfolio');
1.335     banghart 7428:     # Now get possible added metadata fields
1.357     raeburn  7429:     my $added_metadata_fields = &get_added_meta_fieldnames($env{'request.course.id'});
1.347     banghart 7430:     $output .= &Apache::loncommon::start_data_table();
1.258     albertel 7431:     foreach my $field (sort(keys(%metadata_fields))) {
1.265     banghart 7432:         if ($field ne 'courserestricted') {
1.586     raeburn  7433:             $output.= &output_row($r,$field,$metadata_fields{$field});
1.560     damieng  7434:         }
1.255     banghart 7435:     }
1.351     banghart 7436:     my $buttons = (<<ENDButtons);
1.586     raeburn  7437:         <input type="submit" name="restrictmeta" value="$lt{'save'}" />
1.351     banghart 7438:         </form><br />
                   7439:         <form method="post" action="/adm/parmset?action=addmetadata" name="form1">
1.586     raeburn  7440:         <input type="submit" name="restrictmeta" value="$lt{'addm'}" />
1.351     banghart 7441:         </form>
                   7442:         <br />
                   7443:         <form method="post" action="/adm/parmset?action=ordermetadata" name="form2">
1.586     raeburn  7444:         <input type="submit" name="restrictmeta" value="$lt{'ordm'}" />
1.351     banghart 7445: ENDButtons
1.337     banghart 7446:     my $added_flag = 1;
1.335     banghart 7447:     foreach my $field (sort(keys(%$added_metadata_fields))) {
1.586     raeburn  7448:         $output.= &output_row($r,$field,$$added_metadata_fields{$field},$added_flag);
1.335     banghart 7449:     }
1.347     banghart 7450:     $output .= &Apache::loncommon::end_data_table();
1.446     bisitz   7451:     $r->print(<<ENDenv);
1.259     banghart 7452:         <form method="post" action="/adm/parmset?action=setrestrictmeta" name="form">
1.244     banghart 7453:         $output
1.351     banghart 7454:         $buttons
1.340     banghart 7455:         </form>
1.244     banghart 7456: ENDenv
1.507     www      7457:     &endSettingsScreen($r);
1.280     albertel 7458:     $r->print(&Apache::loncommon::end_page());
1.240     banghart 7459:     return 'ok';
                   7460: }
1.416     jms      7461: 
                   7462: 
1.563     damieng  7463: # Returns metadata fields that have been manually added.
                   7464: #
                   7465: # @param {string} $cid - course id
                   7466: # @returns {hash reference} - hash field name -> field title (not localized)
1.335     banghart 7467: sub get_added_meta_fieldnames {
1.357     raeburn  7468:     my ($cid) = @_;
1.335     banghart 7469:     my %fields;
                   7470:     foreach my $key(%env) {
1.357     raeburn  7471:         if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) {
1.335     banghart 7472:             my $field_name = $1;
                   7473:             my ($display_field_name) = $env{$key};
                   7474:             $fields{$field_name} = $display_field_name;
                   7475:         }
                   7476:     }
                   7477:     return \%fields;
                   7478: }
1.416     jms      7479: 
                   7480: 
1.563     damieng  7481: # Returns metadata fields that have been manually added and deleted.
                   7482: #
                   7483: # @param {string} $cid - course id
                   7484: # @returns {hash reference} - hash field name -> field title (not localized)
1.339     banghart 7485: sub get_deleted_meta_fieldnames {
1.357     raeburn  7486:     my ($cid) = @_;
1.339     banghart 7487:     my %fields;
                   7488:     foreach my $key(%env) {
1.357     raeburn  7489:         if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) {
1.339     banghart 7490:             my $field_name = $1;
                   7491:             if ($env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.options'} =~ m/deleted/) {
                   7492:                 my ($display_field_name) = $env{$key};
                   7493:                 $fields{$field_name} = $display_field_name;
                   7494:             }
                   7495:         }
                   7496:     }
                   7497:     return \%fields;
                   7498: }
1.560     damieng  7499: 
                   7500: 
                   7501: ##################################################
                   7502: # PARAMETER SETTINGS DEFAULT ACTIONS
                   7503: ##################################################
                   7504: 
                   7505: # UI to change parameter setting default actions
1.563     damieng  7506: #
                   7507: # @param {Apache2::RequestRec} $r - the Apache request
1.220     www      7508: sub defaultsetter {
1.280     albertel 7509:     my ($r) = @_;
                   7510: 
1.414     droeschl 7511:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setdefaults',
1.473     amueller 7512:         text=>"Set Defaults"});
1.531     raeburn  7513:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7514:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   7515:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.446     bisitz   7516:     my $start_page =
1.531     raeburn  7517:         &Apache::loncommon::start_page('Parameter Setting Default Actions');
1.298     albertel 7518:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Defaults');
1.507     www      7519:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  7520:     &startSettingsScreen($r,'parmset',$crstype);
1.507     www      7521:     $r->print('<form method="post" action="/adm/parmset?action=setdefaults" name="defaultform">');
1.280     albertel 7522: 
1.221     www      7523:     my @ids=();
                   7524:     my %typep=();
                   7525:     my %keyp=();
                   7526:     my %allparms=();
                   7527:     my %allparts=();
                   7528:     my %allmaps=();
                   7529:     my %mapp=();
                   7530:     my %symbp=();
                   7531:     my %maptitles=();
                   7532:     my %uris=();
                   7533:     my %keyorder=&standardkeyorder();
                   7534:     my %defkeytype=();
                   7535: 
1.446     bisitz   7536:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 7537:                 \%mapp, \%symbp,\%maptitles,\%uris,
                   7538:                 \%keyorder,\%defkeytype);
1.224     www      7539:     if ($env{'form.storerules'}) {
1.560     damieng  7540:         my %newrules=();
                   7541:         my @delrules=();
                   7542:         my %triggers=();
                   7543:         foreach my $key (keys(%env)) {
1.225     albertel 7544:             if ($key=~/^form\.(\w+)\_action$/) {
1.560     damieng  7545:                 my $tempkey=$1;
                   7546:                 my $action=$env{$key};
1.226     www      7547:                 if ($action) {
1.560     damieng  7548:                     $newrules{$tempkey.'_action'}=$action;
                   7549:                     if ($action ne 'default') {
                   7550:                         my ($whichaction,$whichparm)=($action=~/^(.*\_)([^\_]+)$/);
                   7551:                         $triggers{$whichparm}.=$tempkey.':';
                   7552:                     }
                   7553:                     $newrules{$tempkey.'_type'}=$defkeytype{$tempkey};
                   7554:                     if (&isdateparm($defkeytype{$tempkey})) {
                   7555:                         $newrules{$tempkey.'_days'}=$env{'form.'.$tempkey.'_days'};
                   7556:                         $newrules{$tempkey.'_hours'}=$env{'form.'.$tempkey.'_hours'};
                   7557:                         $newrules{$tempkey.'_min'}=$env{'form.'.$tempkey.'_min'};
                   7558:                         $newrules{$tempkey.'_sec'}=$env{'form.'.$tempkey.'_sec'};
                   7559:                     } else {
                   7560:                         $newrules{$tempkey.'_value'}=$env{'form.'.$tempkey.'_value'};
                   7561:                         $newrules{$tempkey.'_triggervalue'}=$env{'form.'.$tempkey.'_triggervalue'};
                   7562:                     }
                   7563:                 } else {
                   7564:                     push(@delrules,$tempkey.'_action');
                   7565:                     push(@delrules,$tempkey.'_type');
                   7566:                     push(@delrules,$tempkey.'_hours');
                   7567:                     push(@delrules,$tempkey.'_min');
                   7568:                     push(@delrules,$tempkey.'_sec');
                   7569:                     push(@delrules,$tempkey.'_value');
                   7570:                 }
1.473     amueller 7571:             }
                   7572:         }
1.560     damieng  7573:         foreach my $key (keys(%allparms)) {
                   7574:             $newrules{$key.'_triggers'}=$triggers{$key};
1.473     amueller 7575:         }
1.560     damieng  7576:         &Apache::lonnet::put('parmdefactions',\%newrules,$cdom,$cnum);
                   7577:         &Apache::lonnet::del('parmdefactions',\@delrules,$cdom,$cnum);
                   7578:         &resetrulescache();
1.224     www      7579:     }
1.227     www      7580:     my %lt=&Apache::lonlocal::texthash('days' => 'Days',
1.473     amueller 7581:                        'hours' => 'Hours',
                   7582:                        'min' => 'Minutes',
                   7583:                        'sec' => 'Seconds',
                   7584:                        'yes' => 'Yes',
                   7585:                        'no' => 'No');
1.222     www      7586:     my @standardoptions=('','default');
                   7587:     my @standarddisplay=('',&mt('Default value when manually setting'));
                   7588:     my @dateoptions=('','default');
                   7589:     my @datedisplay=('',&mt('Default value when manually setting'));
                   7590:     foreach my $tempkey (&keysindisplayorder(\%allparms,\%keyorder)) {
1.560     damieng  7591:         unless ($tempkey) { next; }
                   7592:         push @standardoptions,'when_setting_'.$tempkey;
                   7593:         push @standarddisplay,&mt('Automatically set when setting ').$tempkey;
                   7594:         if (&isdateparm($defkeytype{$tempkey})) {
                   7595:             push @dateoptions,'later_than_'.$tempkey;
                   7596:             push @datedisplay,&mt('Automatically set later than ').$tempkey;
                   7597:             push @dateoptions,'earlier_than_'.$tempkey;
                   7598:             push @datedisplay,&mt('Automatically set earlier than ').$tempkey;
                   7599:         }
1.222     www      7600:     }
1.563     damieng  7601:     $r->print(&mt('Manual setting rules apply to all interfaces.').'<br />'.
                   7602:         &mt('Automatic setting rules apply to table mode interfaces only.'));
1.318     albertel 7603:     $r->print("\n".&Apache::loncommon::start_data_table().
1.473     amueller 7604:           &Apache::loncommon::start_data_table_header_row().
                   7605:           "<th>".&mt('Rule for parameter').'</th><th>'.
                   7606:           &mt('Action').'</th><th>'.&mt('Value').'</th>'.
                   7607:           &Apache::loncommon::end_data_table_header_row());
1.221     www      7608:     foreach my $tempkey (&keysindisplayorder(\%allparms,\%keyorder)) {
1.560     damieng  7609:         unless ($tempkey) { next; }
                   7610:         $r->print("\n".&Apache::loncommon::start_data_table_row().
                   7611:             "<td>".$allparms{$tempkey}."\n<br />(".$tempkey.')</td><td>');
                   7612:         my $action=&rulescache($tempkey.'_action');
                   7613:         $r->print('<select name="'.$tempkey.'_action">');
                   7614:         if (&isdateparm($defkeytype{$tempkey})) {
                   7615:             for (my $i=0;$i<=$#dateoptions;$i++) {
                   7616:             if ($dateoptions[$i]=~/\_$tempkey$/) { next; }
                   7617:             $r->print("\n<option value='$dateoptions[$i]'".
                   7618:                 ($dateoptions[$i] eq $action?' selected="selected"':'').
                   7619:                 ">$datedisplay[$i]</option>");
                   7620:             }
                   7621:         } else {
                   7622:             for (my $i=0;$i<=$#standardoptions;$i++) {
                   7623:             if ($standardoptions[$i]=~/\_$tempkey$/) { next; }
                   7624:             $r->print("\n<option value='$standardoptions[$i]'".
                   7625:                 ($standardoptions[$i] eq $action?' selected="selected"':'').
                   7626:                 ">$standarddisplay[$i]</option>");
                   7627:             }
1.473     amueller 7628:         }
1.560     damieng  7629:         $r->print('</select>');
                   7630:         unless (&isdateparm($defkeytype{$tempkey})) {
                   7631:             $r->print("\n<br />".&mt('Triggering value(s) of other parameter (optional, comma-separated):').
                   7632:                 '<input type="text" size="20" name="'.$tempkey.'_triggervalue" value="'.&rulescache($tempkey.'_triggervalue').'" />');
1.473     amueller 7633:         }
1.560     damieng  7634:         $r->print("\n</td><td>\n");
1.222     www      7635: 
1.221     www      7636:         if (&isdateparm($defkeytype{$tempkey})) {
1.560     damieng  7637:             my $days=&rulescache($tempkey.'_days');
                   7638:             my $hours=&rulescache($tempkey.'_hours');
                   7639:             my $min=&rulescache($tempkey.'_min');
                   7640:             my $sec=&rulescache($tempkey.'_sec');
                   7641:             $r->print(<<ENDINPUTDATE);
                   7642:     <input name="$tempkey\_days" type="text" size="4" value="$days" />$lt{'days'}<br />
                   7643:     <input name="$tempkey\_hours" type="text" size="4" value="$hours" />$lt{'hours'}<br />
                   7644:     <input name="$tempkey\_min" type="text" size="4" value="$min" />$lt{'min'}<br />
                   7645:     <input name="$tempkey\_sec" type="text" size="4" value="$sec" />$lt{'sec'}
1.564     raeburn  7646: ENDINPUTDATE
1.560     damieng  7647:         } elsif ($defkeytype{$tempkey} eq 'string_yesno') {
                   7648:                 my $yeschecked='';
                   7649:                 my $nochecked='';
                   7650:                 if (&rulescache($tempkey.'_value') eq 'yes') { $yeschecked=' checked="checked"'; }
                   7651:                 if (&rulescache($tempkey.'_value') eq 'no') { $nochecked=' checked="checked"'; }
                   7652: 
                   7653:             $r->print(<<ENDYESNO);
                   7654:     <label><input type="radio" name="$tempkey\_value" value="yes"$yeschecked /> $lt{'yes'}</label><br />
                   7655:     <label><input type="radio" name="$tempkey\_value" value="no"$nochecked /> $lt{'no'}</label>
1.564     raeburn  7656: ENDYESNO
1.221     www      7657:         } else {
1.560     damieng  7658:             $r->print('<input type="text" size="20" name="'.$tempkey.'_value" value="'.&rulescache($tempkey.'_value').'" />');
                   7659:         }
1.318     albertel 7660:         $r->print('</td>'.&Apache::loncommon::end_data_table_row());
1.221     www      7661:     }
1.318     albertel 7662:     $r->print(&Apache::loncommon::end_data_table().
1.473     amueller 7663:           "\n".'<input type="submit" name="storerules" value="'.
1.507     www      7664:           &mt('Save').'" /></form>'."\n");
                   7665:     &endSettingsScreen($r);
                   7666:     $r->print(&Apache::loncommon::end_page());
1.220     www      7667:     return;
                   7668: }
1.193     albertel 7669: 
1.560     damieng  7670: ##################################################
                   7671: # PARAMETER CHANGES LOG
                   7672: ##################################################
                   7673: 
1.563     damieng  7674: # Returns some info for a parameter log entry.
                   7675: # Returned entries:
                   7676: # $realm - HTML title for the parameter level and resource
                   7677: # $section - parameter section
                   7678: # $name - parameter name
                   7679: # $part - parameter part
                   7680: # $what - $part.'.'.$name
                   7681: # $middle - resource symb ?
                   7682: # $uname - user name (same as given)
                   7683: # $udom - user domain (same as given)
                   7684: # $issection - section or group name
                   7685: # $realmdescription - title for the parameter level and resource (without using HTML)
                   7686: #
                   7687: # @param {string} $key - parameter log key
                   7688: # @param {string} $uname - user name
                   7689: # @param {string} $udom - user domain
                   7690: # @param {boolean} $typeflag - .type log entry
                   7691: # @returns {Array}
1.290     www      7692: sub components {
1.581     raeburn  7693:     my ($key,$uname,$udom,$typeflag)=@_;
1.330     albertel 7694: 
                   7695:     if ($typeflag) {
1.560     damieng  7696:         $key=~s/\.type$//;
1.290     www      7697:     }
1.330     albertel 7698: 
                   7699:     my ($middle,$part,$name)=
1.572     damieng  7700:         ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.291     www      7701:     my $issection;
1.330     albertel 7702: 
1.290     www      7703:     my $section=&mt('All Students');
                   7704:     if ($middle=~/^\[(.*)\]/) {
1.560     damieng  7705:         $issection=$1;
                   7706:         $section=&mt('Group/Section').': '.$issection;
                   7707:         $middle=~s/^\[(.*)\]//;
1.290     www      7708:     }
                   7709:     $middle=~s/\.+$//;
                   7710:     $middle=~s/^\.+//;
1.291     www      7711:     if ($uname) {
1.560     damieng  7712:         $section=&mt('User').": ".&Apache::loncommon::plainname($uname,$udom);
                   7713:         $issection='';
1.291     www      7714:     }
1.316     albertel 7715:     my $realm='<span class="LC_parm_scope_all">'.&mt('All Resources').'</span>';
1.446     bisitz   7716:     my $realmdescription=&mt('all resources');
1.556     raeburn  7717:     if ($middle=~/^(.+)\_\_\_\((all|rec)\)$/) {
                   7718:         my $mapurl = $1;
                   7719:         my $maplevel = $2;
                   7720:         my $leveltitle = &mt('Folder/Map');
                   7721:         if ($maplevel eq 'rec') {
                   7722:             $leveltitle = &mt('Recursive');
                   7723:         }
1.560     damieng  7724:         $realm='<span class="LC_parm_scope_folder">'.$leveltitle.
                   7725:             ': '.&Apache::lonnet::gettitle($mapurl).' <span class="LC_parm_folder"><br />('.
                   7726:             $mapurl.')</span></span>';
                   7727:         $realmdescription=&mt('folder').' '.&Apache::lonnet::gettitle($mapurl);
                   7728:     } elsif ($middle) {
                   7729:         my ($map,$id,$url)=&Apache::lonnet::decode_symb($middle);
                   7730:         $realm='<span class="LC_parm_scope_resource">'.&mt('Resource').
                   7731:             ': '.&Apache::lonnet::gettitle($middle).' <br /><span class="LC_parm_symb">('.$url.
                   7732:             ' in '.$map.' id: '.$id.')</span></span>';
                   7733:         $realmdescription=&mt('resource').' '.&Apache::lonnet::gettitle($middle);
1.290     www      7734:     }
1.291     www      7735:     my $what=$part.'.'.$name;
1.330     albertel 7736:     return ($realm,$section,$name,$part,
1.473     amueller 7737:         $what,$middle,$uname,$udom,$issection,$realmdescription);
1.290     www      7738: }
1.293     www      7739: 
1.563     damieng  7740: my %standard_parms; # hash parameter name -> parameter title (not localized)
                   7741: my %standard_parms_types; # hash parameter name -> parameter type
1.416     jms      7742: 
1.563     damieng  7743: # Reads parameter info from packages.tab into %standard_parms.
1.328     albertel 7744: sub load_parameter_names {
1.583     raeburn  7745:     open(my $config,"<","$Apache::lonnet::perlvar{'lonTabDir'}/packages.tab");
1.328     albertel 7746:     while (my $configline=<$config>) {
1.560     damieng  7747:         if ($configline !~ /\S/ || $configline=~/^\#/) { next; }
                   7748:         chomp($configline);
                   7749:         my ($short,$plain)=split(/:/,$configline);
                   7750:         my (undef,$name,$type)=split(/\&/,$short,3);
                   7751:         if ($type eq 'display') {
                   7752:             $standard_parms{$name} = $plain;
1.469     raeburn  7753:         } elsif ($type eq 'type') {
1.560     damieng  7754:                 $standard_parms_types{$name} = $plain;
1.469     raeburn  7755:         }
1.328     albertel 7756:     }
                   7757:     close($config);
                   7758:     $standard_parms{'int_pos'}      = 'Positive Integer';
                   7759:     $standard_parms{'int_zero_pos'} = 'Positive Integer or Zero';
1.575     raeburn  7760:     $standard_parms{'scoreformat'}  = 'Format for display of score';
1.328     albertel 7761: }
                   7762: 
1.563     damieng  7763: # Returns a parameter title for standard parameters, the name for others.
                   7764: #
                   7765: # @param {string} $name - parameter name
                   7766: # @returns {string}
1.292     www      7767: sub standard_parameter_names {
                   7768:     my ($name)=@_;
1.328     albertel 7769:     if (!%standard_parms) {
1.560     damieng  7770:         &load_parameter_names();
1.328     albertel 7771:     }
1.292     www      7772:     if ($standard_parms{$name}) {
1.560     damieng  7773:         return $standard_parms{$name};
1.446     bisitz   7774:     } else {
1.560     damieng  7775:         return $name;
1.292     www      7776:     }
                   7777: }
1.290     www      7778: 
1.563     damieng  7779: # Returns a parameter type for standard parameters, undef for others.
                   7780: #
                   7781: # @param {string} $name - parameter name
                   7782: # @returns {string}
1.469     raeburn  7783: sub standard_parameter_types {
                   7784:     my ($name)=@_;
                   7785:     if (!%standard_parms_types) {
                   7786:         &load_parameter_names();
                   7787:     }
                   7788:     if ($standard_parms_types{$name}) {
                   7789:         return $standard_parms_types{$name};
                   7790:     }
                   7791:     return;
                   7792: }
1.309     www      7793: 
1.563     damieng  7794: # Returns a parameter level title (not localized) from the parameter level name.
                   7795: #
                   7796: # @param {string} $name - parameter level name (recognized: resourcelevel|maplevel|maplevelrecurse|courselevel)
                   7797: # @returns {string}
1.557     raeburn  7798: sub standard_parameter_levels {
                   7799:     my ($name)=@_;
                   7800:     my %levels = (
                   7801:                     'resourcelevel'   => 'a single resource',
                   7802:                     'maplevel'        => 'the enclosing map/folder', 
                   7803:                     'maplevelrecurse' => 'the enclosing map/folder (recursive into sub-folders)',
                   7804:                     'courselevel'     => 'the general (course) level',
                   7805:                  );
                   7806:     if ($levels{$name}) {
                   7807:         return $levels{$name};
                   7808:     }
                   7809:     return;
                   7810: }
                   7811: 
1.560     damieng  7812: # Display log for parameter changes, blog postings, user notification changes.
1.563     damieng  7813: #
                   7814: # @param {Apache2::RequestRec} $r - the Apache request
1.285     albertel 7815: sub parm_change_log {
1.568     raeburn  7816:     my ($r,$parm_permission)=@_;
1.531     raeburn  7817:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7818:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.569     raeburn  7819:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.414     droeschl 7820:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=settable',
1.473     amueller 7821:     text=>"Parameter Change Log"});
1.522     raeburn  7822:     my $js = '<script type="text/javascript">'."\n".
                   7823:              '// <![CDATA['."\n".
                   7824:              &Apache::loncommon::display_filter_js('parmslog')."\n".
                   7825:              '// ]]>'."\n".
                   7826:              '</script>'."\n";
                   7827:     $r->print(&Apache::loncommon::start_page('Parameter Change Log',$js));
1.327     albertel 7828:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Parameter Change Log'));
1.531     raeburn  7829:     &startSettingsScreen($r,'parmset',$crstype);
                   7830:     my %parmlog=&Apache::lonnet::dump('nohist_parameterlog',$cdom,$cnum);
1.311     albertel 7831: 
1.301     www      7832:     if ((keys(%parmlog))[0]=~/^error\:/) { undef(%parmlog); }
1.311     albertel 7833: 
1.522     raeburn  7834:     $r->print('<div class="LC_left_float">'.
                   7835:               '<fieldset><legend>'.&mt('Display of Changes').'</legend>'.
                   7836:               '<form action="/adm/parmset?action=parameterchangelog"
1.327     albertel 7837:                      method="post" name="parameterlog">');
1.446     bisitz   7838: 
1.311     albertel 7839:     my %saveable_parameters = ('show' => 'scalar',);
                   7840:     &Apache::loncommon::store_course_settings('parameter_log',
                   7841:                                               \%saveable_parameters);
                   7842:     &Apache::loncommon::restore_course_settings('parameter_log',
                   7843:                                                 \%saveable_parameters);
1.522     raeburn  7844:     $r->print(&Apache::loncommon::display_filter('parmslog').'&nbsp;'."\n".
                   7845:               '<input type="submit" value="'.&mt('Display').'" />'.
                   7846:               '</form></fieldset></div><br clear="all" />');
1.301     www      7847: 
1.568     raeburn  7848:     my $readonly = 1;
                   7849:     if ($parm_permission->{'edit'}) {
                   7850:         undef($readonly);
                   7851:     }
1.531     raeburn  7852:     my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
1.301     www      7853:     $r->print(&Apache::loncommon::start_data_table().&Apache::loncommon::start_data_table_header_row().
1.473     amueller 7854:           '<th>'.&mt('Time').'</th><th>'.&mt('User').'</th><th>'.&mt('Extent').'</th><th>'.&mt('Users').'</th><th>'.
1.568     raeburn  7855:           &mt('Parameter').'</th><th>'.&mt('Part').'</th><th>'.&mt('New Value').'</th>');
                   7856:     unless ($readonly) {
                   7857:         $r->print('<th>'.&mt('Announce').'</th>');
                   7858:     }
                   7859:     $r->print(&Apache::loncommon::end_data_table_header_row());
1.309     www      7860:     my $shown=0;
1.349     www      7861:     my $folder='';
                   7862:     if ($env{'form.displayfilter'} eq 'currentfolder') {
1.560     damieng  7863:         my $last='';
                   7864:         if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
                   7865:                 &GDBM_READER(),0640)) {
                   7866:             $last=$hash{'last_known'};
                   7867:             untie(%hash);
                   7868:         }
                   7869:         if ($last) { ($folder) = &Apache::lonnet::decode_symb($last); }
                   7870:     }
1.595     raeburn  7871:     my $numgroups = 0;
                   7872:     my @groups;
                   7873:     if ($env{'request.course.groups'} ne '') {
                   7874:         @groups = split(/:/,$env{'request.course.groups'});
                   7875:         $numgroups = scalar(@groups);
                   7876:     }
1.560     damieng  7877:     foreach my $id (sort {
                   7878:                 if ($parmlog{$b}{'exe_time'} ne $parmlog{$a}{'exe_time'}) {
                   7879:                     return $parmlog{$b}{'exe_time'} <=>$parmlog{$a}{'exe_time'}
                   7880:                 }
                   7881:                 my $aid = (split('00000',$a))[-1];
                   7882:                 my $bid = (split('00000',$b))[-1];
                   7883:                 return $bid<=>$aid;
1.473     amueller 7884:             } (keys(%parmlog))) {
1.294     www      7885:         my @changes=keys(%{$parmlog{$id}{'logentry'}});
1.560     damieng  7886:         my $count = 0;
                   7887:         my $time =
                   7888:             &Apache::lonlocal::locallocaltime($parmlog{$id}{'exe_time'});
                   7889:         my $plainname =
                   7890:             &Apache::loncommon::plainname($parmlog{$id}{'exe_uname'},
                   7891:                         $parmlog{$id}{'exe_udom'});
                   7892:         my $about_me_link =
                   7893:             &Apache::loncommon::aboutmewrapper($plainname,
                   7894:                             $parmlog{$id}{'exe_uname'},
                   7895:                             $parmlog{$id}{'exe_udom'});
                   7896:         my $send_msg_link='';
1.568     raeburn  7897:         if ((!$readonly) && 
                   7898:             (($parmlog{$id}{'exe_uname'} ne $env{'user.name'})
1.560     damieng  7899:             || ($parmlog{$id}{'exe_udom'} ne $env{'user.domain'}))) {
                   7900:             $send_msg_link ='<br />'.
                   7901:             &Apache::loncommon::messagewrapper(&mt('Send message'),
                   7902:                             $parmlog{$id}{'exe_uname'},
                   7903:                             $parmlog{$id}{'exe_udom'});
                   7904:         }
                   7905:         my $row_start=&Apache::loncommon::start_data_table_row();
                   7906:         my $makenewrow=0;
                   7907:         my %istype=();
                   7908:         my $output;
                   7909:         foreach my $changed (reverse(sort(@changes))) {
                   7910:                 my $value=$parmlog{$id}{'logentry'}{$changed};
                   7911:             my $typeflag = ($changed =~/\.type$/ &&
                   7912:                     !exists($parmlog{$id}{'logentry'}{$changed.'.type'}));
1.330     albertel 7913:             my ($realm,$section,$parmname,$part,$what,$middle,$uname,$udom,$issection,$realmdescription)=
1.581     raeburn  7914:                 &components($changed,$parmlog{$id}{'uname'},$parmlog{$id}{'udom'},$typeflag);
1.560     damieng  7915:             if ($env{'request.course.sec'} ne '') {
1.595     raeburn  7916:                 next if (($issection ne '') && (!(($issection eq $env{'request.course.sec'}) ||
                   7917:                                                   ($numgroups && (grep(/^\Q$issection\E$/,@groups))))));
1.560     damieng  7918:                 if ($uname ne '') {
                   7919:                     my $stusection = &Apache::lonnet::getsection($uname,$udom,$env{'request.course.id'});
                   7920:                     next if (($stusection ne '-1') && ($stusection ne $env{'request.course.sec'})); 
                   7921:                 }
                   7922:             }
                   7923:             if ($env{'form.displayfilter'} eq 'currentfolder') {
                   7924:                 if ($folder) {
                   7925:                     if ($middle!~/^\Q$folder\E/) { next; }
                   7926:                 }
                   7927:             }
                   7928:             if ($typeflag) {
                   7929:                 $istype{$parmname}=$value;
                   7930:                 if (!$env{'form.includetypes'}) { next; }
                   7931:             }
                   7932:             $count++;
                   7933:             if ($makenewrow) {
                   7934:                 $output .= $row_start;
                   7935:             } else {
                   7936:                 $makenewrow=1;
                   7937:             }
1.470     raeburn  7938:             my $parmitem = &standard_parameter_names($parmname);
1.560     damieng  7939:             $output .='<td>'.$realm.'</td><td>'.$section.'</td><td>'.
                   7940:                 &mt($parmitem).'</td><td>'.
                   7941:                 ($part?&mt('Part: [_1]',$part):&mt('All Parts')).'</td><td>';
                   7942:             my $stillactive=0;
                   7943:             if ($parmlog{$id}{'delflag'}) {
                   7944:                 $output .= &mt('Deleted');
                   7945:             } else {
                   7946:                 if ($typeflag) {
1.470     raeburn  7947:                     my $parmitem = &standard_parameter_names($value); 
                   7948:                     $parmitem = &mt($parmitem);
1.560     damieng  7949:                     $output .= &mt('Type: [_1]',$parmitem);
                   7950:                 } else {
1.584     raeburn  7951:                     my $toolsymb;
                   7952:                     if ($middle =~ /ext\.tool$/) {
                   7953:                         $toolsymb = $middle;
                   7954:                     }
1.560     damieng  7955:                     my ($level,@all)=&parmval_by_symb($what,$middle,
1.584     raeburn  7956:                         &Apache::lonnet::metadata($middle,$what,$toolsymb),
1.560     damieng  7957:                         $uname,$udom,$issection,$issection,$courseopt);
1.469     raeburn  7958:                     my $showvalue = $value;
                   7959:                     if ($istype{$parmname} eq '') {
                   7960:                         my $type = &standard_parameter_types($parmname);
                   7961:                         if ($type ne '') {
                   7962:                             if (&isdateparm($type)) {
                   7963:                                 $showvalue =
                   7964:                                     &Apache::lonlocal::locallocaltime($value);
                   7965:                             }
                   7966:                         }
                   7967:                     } else {
1.560     damieng  7968:                         if (&isdateparm($istype{$parmname})) {
                   7969:                             $showvalue = &Apache::lonlocal::locallocaltime($value);
1.622     raeburn  7970:                         } elsif (($istype{$parmname} eq 'string_grace') ||
                   7971:                                  ($istype{$parmname} eq 'string_ip')) {
                   7972:                             $showvalue =~ s/,/, /g;
1.560     damieng  7973:                         }
1.469     raeburn  7974:                     }
                   7975:                     $output .= $showvalue;
1.560     damieng  7976:                     if ($value ne $all[$level]) {
                   7977:                         $output .= '<br /><span class="LC_warning">'.&mt('Not active anymore').'</span>';
                   7978:                     } else {
                   7979:                         $stillactive=1;
                   7980:                     }
                   7981:                 }
1.473     amueller 7982:             }
1.568     raeburn  7983:             $output .= '</td>';
                   7984: 
                   7985:             unless ($readonly) { 
                   7986:                 $output .= '<td>';
                   7987:                 if ($stillactive) {
                   7988:                     my $parmitem = &standard_parameter_names($parmname);
                   7989:                     $parmitem = &mt($parmitem);
                   7990:                     my $title=&mt('Changed [_1]',$parmitem);
                   7991:                     my $description=&mt('Changed [_1] for [_2] to [_3]',
                   7992:                         $parmitem,$realmdescription,
                   7993:                         (&isdateparm($istype{$parmname})?&Apache::lonlocal::locallocaltime($value):$value));
                   7994:                     if (($uname) && ($udom)) {
                   7995:                         $output .=
                   7996:                         &Apache::loncommon::messagewrapper('Notify User',
                   7997:                                                            $uname,$udom,$title,
                   7998:                                                            $description);
                   7999:                     } else {
                   8000:                         $output .=
                   8001:                             &Apache::lonrss::course_blog_link($id,$title,
                   8002:                                                               $description);
                   8003:                     }
1.560     damieng  8004:                 }
1.568     raeburn  8005:                 $output .= '</td>';
1.560     damieng  8006:             }
1.568     raeburn  8007:             $output .= &Apache::loncommon::end_data_table_row();
1.473     amueller 8008:         }
1.560     damieng  8009:         if ($env{'form.displayfilter'} eq 'containing') {
                   8010:             my $wholeentry=$about_me_link.':'.
                   8011:             $parmlog{$id}{'exe_uname'}.':'.$parmlog{$id}{'exe_udom'}.':'.
                   8012:             $output;
                   8013:             if ($wholeentry!~/\Q$env{'form.containingphrase'}\E/i) { next; }
1.473     amueller 8014:         }
1.349     www      8015:         if ($count) {
1.560     damieng  8016:             $r->print($row_start.'<td rowspan="'.$count.'">'.$time.'</td>
                   8017:                         <td rowspan="'.$count.'">'.$about_me_link.
                   8018:             '<br /><tt>'.$parmlog{$id}{'exe_uname'}.
                   8019:                         ':'.$parmlog{$id}{'exe_udom'}.'</tt>'.
                   8020:             $send_msg_link.'</td>'.$output);
                   8021:             $shown++;
                   8022:         }
                   8023:         if (!($env{'form.show'} eq &mt('all')
                   8024:             || $shown<=$env{'form.show'})) { last; }
1.286     www      8025:     }
1.301     www      8026:     $r->print(&Apache::loncommon::end_data_table());
1.507     www      8027:     &endSettingsScreen($r);
1.284     www      8028:     $r->print(&Apache::loncommon::end_page());
                   8029: }
                   8030: 
1.560     damieng  8031: ##################################################
                   8032: # MISC !
                   8033: ##################################################
                   8034: 
1.563     damieng  8035: # Stores slot information.
1.560     damieng  8036: # Used by table UI
1.563     damieng  8037: # FIXME: I don't understand how this can work when the symb is not defined (if only a map was selected)
                   8038: #
                   8039: # @param {string} $slot_name - slot name
                   8040: # @param {string} $cdom - course domain
                   8041: # @param {string} $cnum - course number
                   8042: # @param {string} $symb - resource symb
                   8043: # @param {string} $uname - user name
                   8044: # @param {string} $udom - user domain
                   8045: # @returns {string} - 'ok' or error name
1.437     raeburn  8046: sub update_slots {
                   8047:     my ($slot_name,$cdom,$cnum,$symb,$uname,$udom) = @_;
                   8048:     my %slot=&Apache::lonnet::get_slot($slot_name);
                   8049:     if (!keys(%slot)) {
                   8050:         return 'error: slot does not exist';
                   8051:     }
                   8052:     my $max=$slot{'maxspace'};
                   8053:     if (!defined($max)) { $max=99999; }
                   8054: 
                   8055:     my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum,
                   8056:                                        "^$slot_name\0");
                   8057:     my ($tmp)=%consumed;
                   8058:     if ($tmp=~/^error: 2 / ) {
                   8059:         return 'error: unable to determine current slot status';
                   8060:     }
                   8061:     my $last=0;
                   8062:     foreach my $key (keys(%consumed)) {
                   8063:         my $num=(split('\0',$key))[1];
                   8064:         if ($num > $last) { $last=$num; }
                   8065:         if ($consumed{$key}->{'name'} eq $uname.':'.$udom) {
                   8066:             return 'ok';
                   8067:         }
                   8068:     }
                   8069: 
                   8070:     if (scalar(keys(%consumed)) >= $max) {
                   8071:         return 'error: no space left in slot';
                   8072:     }
                   8073:     my $wanted=$last+1;
                   8074: 
                   8075:     my %reservation=('name'      => $uname.':'.$udom,
                   8076:                      'timestamp' => time,
                   8077:                      'symb'      => $symb);
                   8078: 
                   8079:     my $success=&Apache::lonnet::newput('slot_reservations',
                   8080:                                         {"$slot_name\0$wanted" =>
                   8081:                                              \%reservation},
                   8082:                                         $cdom, $cnum);
1.438     raeburn  8083:     if ($success eq 'ok') {
                   8084:         my %storehash = (
                   8085:                           symb    => $symb,
                   8086:                           slot    => $slot_name,
                   8087:                           action  => 'reserve',
                   8088:                           context => 'parameter',
                   8089:                         );
1.526     raeburn  8090:         &Apache::lonnet::write_log('course','slotreservationslog',\%storehash,
1.524     raeburn  8091:                                    '',$uname,$udom,$cnum,$cdom);
1.438     raeburn  8092: 
1.526     raeburn  8093:         &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash,
1.524     raeburn  8094:                                    '',$uname,$udom,$uname,$udom);
1.438     raeburn  8095:     }
1.437     raeburn  8096:     return $success;
                   8097: }
                   8098: 
1.563     damieng  8099: # Deletes a slot reservation.
1.560     damieng  8100: # Used by table UI
1.563     damieng  8101: # FIXME: I don't understand how this can work when the symb is not defined (if only a map was selected)
                   8102: #
                   8103: # @param {string} $slot_name - slot name
                   8104: # @param {string} $cdom - course domain
                   8105: # @param {string} $cnum - course number
                   8106: # @param {string} $uname - user name
                   8107: # @param {string} $udom - user domain
                   8108: # @param {string} $symb - resource symb
                   8109: # @returns {string} - 'ok' or error name
1.437     raeburn  8110: sub delete_slots {
                   8111:     my ($slot_name,$cdom,$cnum,$uname,$udom,$symb) = @_;
                   8112:     my $delresult;
                   8113:     my %consumed = &Apache::lonnet::dump('slot_reservations',$cdom,
                   8114:                                          $cnum, "^$slot_name\0");
                   8115:     if (&Apache::lonnet::error(%consumed)) {
                   8116:         return 'error: unable to determine current slot status';
                   8117:     }
                   8118:     my ($tmp)=%consumed;
                   8119:     if ($tmp=~/^error: 2 /) {
                   8120:         return 'error: unable to determine current slot status';
                   8121:     }
                   8122:     foreach my $key (keys(%consumed)) {
                   8123:         if ($consumed{$key}->{'name'} eq $uname.':'.$udom) {
                   8124:             my $num=(split('\0',$key))[1];
                   8125:             my $entry = $slot_name.'\0'.$num;
                   8126:             $delresult = &Apache::lonnet::del('slot_reservations',[$entry],
                   8127:                                               $cdom,$cnum);
                   8128:             if ($delresult eq 'ok') {
                   8129:                 my %storehash = (
                   8130:                                   symb    => $symb,
                   8131:                                   slot    => $slot_name,
                   8132:                                   action  => 'release',
                   8133:                                   context => 'parameter',
                   8134:                                 );
1.526     raeburn  8135:                 &Apache::lonnet::write_log('course','slotreservationslog',\%storehash,
1.524     raeburn  8136:                                            1,$uname,$udom,$cnum,$cdom);
1.526     raeburn  8137:                 &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash,
1.524     raeburn  8138:                                            1,$uname,$udom,$uname,$udom);
1.437     raeburn  8139:             }
                   8140:         }
                   8141:     }
                   8142:     return $delresult;
                   8143: }
                   8144: 
1.563     damieng  8145: # Returns true if there is a current course.
1.560     damieng  8146: # Used by handler
1.563     damieng  8147: #
                   8148: # @returns {boolean}
1.355     albertel 8149: sub check_for_course_info {
                   8150:     my $navmap = Apache::lonnavmaps::navmap->new();
                   8151:     return 1 if ($navmap);
                   8152:     return 0;
                   8153: }
                   8154: 
1.563     damieng  8155: # Returns the current course host and host LON-CAPA version.
                   8156: #
                   8157: # @returns {Array} - (course hostname, major version number, minor version number)
1.514     raeburn  8158: sub parameter_release_vars { 
1.504     raeburn  8159:    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   8160:    my $chome = $env{'course.'.$env{'request.course.id'}.'.home'};
                   8161:    my $chostname = &Apache::lonnet::hostname($chome);
                   8162:    my ($cmajor,$cminor) = 
                   8163:        split(/\./,&Apache::lonnet::get_server_loncaparev($cdom,$chome));
                   8164:    return ($chostname,$cmajor,$cminor);
                   8165: }
                   8166: 
1.563     damieng  8167: # Checks if the course host version can handle a parameter required version,
                   8168: # and if it does, stores the release needed for the course.
                   8169: #
                   8170: # @param {string} $name - parameter name
                   8171: # @param {string} $value - parameter value
                   8172: # @param {string} $valmatch - name of the test used for checking the value
                   8173: # @param {string} $namematch - name of the test used for checking the name
                   8174: # @param {string} $needsrelease - version needed by the parameter, major.minor
                   8175: # @param {integer} $cmajor - course major version number
                   8176: # @param {integer} $cminor - course minor version number
                   8177: # @returns {boolean} - true if a newer version is needed
1.514     raeburn  8178: sub parameter_releasecheck {
1.557     raeburn  8179:     my ($name,$value,$valmatch,$namematch,$needsrelease,$cmajor,$cminor) = @_;
1.504     raeburn  8180:     my $needsnewer;
                   8181:     my ($needsmajor,$needsminor) = split(/\./,$needsrelease);
                   8182:     if (($cmajor < $needsmajor) || 
                   8183:         ($cmajor == $needsmajor && $cminor < $needsminor)) {
                   8184:         $needsnewer = 1;
1.557     raeburn  8185:     } elsif ($name) {
                   8186:         if ($valmatch) {
                   8187:             &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.'::'.$valmatch.':'});
                   8188:         } elsif ($value) { 
                   8189:             &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.':'.$value.'::'});
                   8190:         }
                   8191:     } elsif ($namematch) {
                   8192:         &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter::::'.$namematch});
1.504     raeburn  8193:     }
                   8194:     return $needsnewer;
                   8195: }
                   8196: 
1.568     raeburn  8197: sub get_permission {
                   8198:     my %permission;
                   8199:     my $allowed = 0;
                   8200:     return (\%permission,$allowed) unless ($env{'request.course.id'});
                   8201:     if ((&Apache::lonnet::allowed('opa',$env{'request.course.id'})) ||
                   8202:         (&Apache::lonnet::allowed('opa',$env{'request.course.id'}.'/'.
                   8203:                   $env{'request.course.sec'}))) {
                   8204:         %permission= (
                   8205:                        'edit'               => 1,
                   8206:                        'set'                => 1,
                   8207:                        'setoverview'        => 1,
                   8208:                        'addmetadata'        => 1,
                   8209:                        'ordermetadata'      => 1,
                   8210:                        'setrestrictmeta'    => 1,
                   8211:                        'newoverview'        => 1,
                   8212:                        'setdefaults'        => 1,
                   8213:                        'settable'           => 1,
                   8214:                        'parameterchangelog' => 1,
                   8215:                        'cleanparameters'    => 1,
                   8216:                        'dateshift1'         => 1,
                   8217:                        'dateshift2'         => 1,
                   8218:                        'helper'             => 1,
                   8219:          );
                   8220:     } elsif ((&Apache::lonnet::allowed('vpa',$env{'request.course.id'})) ||
                   8221:              (&Apache::lonnet::allowed('vpa',$env{'request.course.id'}.'/'.
                   8222:                   $env{'request.course.sec'}))) {
                   8223:         %permission = (
                   8224:                        'set'                => 1,
                   8225:                        'settable'           => 1,
                   8226:                        'newoverview'        => 1,
                   8227:                        'setoverview'        => 1,
                   8228:                        'parameterchangelog' => 1,
                   8229:                       );
                   8230:     }
                   8231:     foreach my $perm (values(%permission)) {
                   8232:         if ($perm) { $allowed=1; last; }
                   8233:     }
                   8234:     return (\%permission,$allowed);
                   8235: }
                   8236: 
1.560     damieng  8237: ##################################################
                   8238: # HANDLER
                   8239: ##################################################
                   8240: 
                   8241: # Main handler for lonparmset.
                   8242: # Sub called based on request parameters action and command:
                   8243: # no command or action: print_main_menu
                   8244: # command 'set': assessparms (direct access to table mode for a resource)
                   8245: #                (this can also be accessed simply with the symb parameter)
                   8246: # action 'setoverview': overview (display all existing parameter settings)
                   8247: # action 'addmetadata': addmetafield (called to add a portfolio metadata field)
                   8248: # action 'ordermetadata': order_meta_fields (called to order portfolio metadata fields)
                   8249: # action 'setrestrictmeta': setrestrictmeta (display or save portfolio metadata)
                   8250: # action 'newoverview': newoverview (overview mode)
                   8251: # action 'setdefaults': defaultsetter (UI to change parameter setting default actions)
                   8252: # action 'settable': assessparms (table mode)
                   8253: # action 'parameterchangelog': parm_change_log (display log for parameter changes,
                   8254: #                              blog postings, user notification changes)
                   8255: # action 'cleanparameters': clean_parameters (unused)
                   8256: # action 'dateshift1': date_shift_one (overview mode, shift all dates)
                   8257: # action 'dateshift2': date_shift_two (overview mode, shift all dates)
1.30      www      8258: sub handler {
1.43      albertel 8259:     my $r=shift;
1.30      www      8260: 
1.376     albertel 8261:     &reset_caches();
                   8262: 
1.414     droeschl 8263:     &Apache::loncommon::content_type($r,'text/html');
                   8264:     $r->send_http_header;
                   8265:     return OK if $r->header_only;
                   8266: 
1.193     albertel 8267:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.473     amueller 8268:                         ['action','state',
1.205     www      8269:                                              'pres_marker',
                   8270:                                              'pres_value',
1.206     www      8271:                                              'pres_type',
1.506     www      8272:                                              'filter','part',
1.390     www      8273:                                              'udom','uname','symb','serial','timebase']);
1.131     www      8274: 
1.83      bowersj2 8275: 
1.193     albertel 8276:     &Apache::lonhtmlcommon::clear_breadcrumbs();
1.194     albertel 8277:     &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/parmset",
1.507     www      8278:                         text=>"Content and Problem Settings",
1.473     amueller 8279:                         faq=>10,
                   8280:                         bug=>'Instructor Interface',
1.442     droeschl 8281:                                             help =>
                   8282:                                             'Parameter_Manager,Course_Environment,Parameter_Helper,Parameter_Overview,Table_Mode'});
1.203     www      8283: 
1.30      www      8284: # ----------------------------------------------------- Needs to be in a course
1.568     raeburn  8285:     my ($parm_permission,$allowed) = &get_permission();
1.355     albertel 8286:     my $exists = &check_for_course_info();
                   8287: 
1.568     raeburn  8288:     if ($env{'request.course.id'} && $allowed && $exists) {
1.193     albertel 8289:         #
                   8290:         # Main switch on form.action and form.state, as appropriate
                   8291:         #
                   8292:         # Check first if coming from someone else headed directly for
                   8293:         #  the table mode
1.568     raeburn  8294:         if (($parm_permission->{'set'}) && 
                   8295:             ((($env{'form.command'} eq 'set') && ($env{'form.url'})
                   8296:                 && (!$env{'form.dis'})) || ($env{'form.symb'}))) {
                   8297:             &assessparms($r,$parm_permission);
1.193     albertel 8298:         } elsif (! exists($env{'form.action'})) {
                   8299:             &print_main_menu($r,$parm_permission);
1.568     raeburn  8300:         } elsif (!$parm_permission->{$env{'form.action'}}) {
                   8301:             &print_main_menu($r,$parm_permission);
1.414     droeschl 8302:         } elsif ($env{'form.action'} eq 'setoverview') {
1.568     raeburn  8303:             &overview($r,$parm_permission);
1.560     damieng  8304:         } elsif ($env{'form.action'} eq 'addmetadata') {
                   8305:             &addmetafield($r);
                   8306:         } elsif ($env{'form.action'} eq 'ordermetadata') {
                   8307:             &order_meta_fields($r);
1.414     droeschl 8308:         } elsif ($env{'form.action'} eq 'setrestrictmeta') {
1.560     damieng  8309:             &setrestrictmeta($r);
1.414     droeschl 8310:         } elsif ($env{'form.action'} eq 'newoverview') {
1.568     raeburn  8311:             &newoverview($r,$parm_permission);
1.414     droeschl 8312:         } elsif ($env{'form.action'} eq 'setdefaults') {
1.560     damieng  8313:             &defaultsetter($r);
                   8314:         } elsif ($env{'form.action'} eq 'settable') {
1.568     raeburn  8315:             &assessparms($r,$parm_permission);
1.414     droeschl 8316:         } elsif ($env{'form.action'} eq 'parameterchangelog') {
1.568     raeburn  8317:             &parm_change_log($r,$parm_permission);
1.414     droeschl 8318:         } elsif ($env{'form.action'} eq 'cleanparameters') {
1.560     damieng  8319:             &clean_parameters($r);
1.414     droeschl 8320:         } elsif ($env{'form.action'} eq 'dateshift1') {
1.390     www      8321:             &date_shift_one($r);
1.414     droeschl 8322:         } elsif ($env{'form.action'} eq 'dateshift2') {
1.390     www      8323:             &date_shift_two($r);
1.446     bisitz   8324:         }
1.43      albertel 8325:     } else {
1.1       www      8326: # ----------------------------- Not in a course, or not allowed to modify parms
1.560     damieng  8327:         if ($exists) {
                   8328:             $env{'user.error.msg'}=
                   8329:             "/adm/parmset:opa:0:0:Cannot modify assessment parameters";
                   8330:         } else {
                   8331:             $env{'user.error.msg'}=
                   8332:             "/adm/parmset::0:1:Course environment gone, reinitialize the course";
                   8333:         }
                   8334:         return HTTP_NOT_ACCEPTABLE;
1.43      albertel 8335:     }
1.376     albertel 8336:     &reset_caches();
                   8337: 
1.43      albertel 8338:     return OK;
1.1       www      8339: }
                   8340: 
                   8341: 1;
                   8342: __END__
                   8343: 
                   8344: 

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