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

1.1       www         1: # The LearningOnline Network with CAPA
                      2: # Handler to set parameters for assessments
                      3: #
1.623   ! raeburn     4: # $Id: lonparmset.pm,v 1.622 2025/06/28 14:34:46 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.549     raeburn  6399: <form method="post" action="/adm/parmset?action=newoverview" name="parmform" onsubmit="return validateParms();">
1.208     www      6400: ENDOVER
1.211     www      6401:     my @ids=();
                   6402:     my %typep=();
                   6403:     my %keyp=();
                   6404:     my %allparms=();
                   6405:     my %allparts=();
                   6406:     my %allmaps=();
                   6407:     my %mapp=();
                   6408:     my %symbp=();
                   6409:     my %maptitles=();
                   6410:     my %uris=();
                   6411:     my %keyorder=&standardkeyorder();
                   6412:     my %defkeytype=();
                   6413: 
                   6414:     my %alllevs=();
                   6415:     $alllevs{'Resource Level'}='full';
1.215     www      6416:     $alllevs{'Map/Folder Level'}='map';
1.211     www      6417:     $alllevs{'Course Level'}='general';
                   6418: 
                   6419:     my $csec=$env{'form.csec'};
1.269     raeburn  6420:     my $cgroup=$env{'form.cgroup'};
1.211     www      6421: 
                   6422:     my @pscat=&Apache::loncommon::get_env_multiple('form.pscat');
                   6423:     my $pschp=$env{'form.pschp'};
1.506     www      6424: 
1.211     www      6425:     my @psprt=&Apache::loncommon::get_env_multiple('form.psprt');
1.516     www      6426:     if (!@psprt) { $psprt[0]='all'; }
1.211     www      6427: 
1.446     bisitz   6428:     my @selected_sections =
1.473     amueller 6429:     &Apache::loncommon::get_env_multiple('form.Section');
1.211     www      6430:     @selected_sections = ('all') if (! @selected_sections);
1.374     albertel 6431:     foreach my $sec (@selected_sections) {
                   6432:         if ($sec eq 'all') {
1.211     www      6433:             @selected_sections = ('all');
                   6434:         }
                   6435:     }
1.552     raeburn  6436:     if ($env{'request.course.sec'} ne '') {
                   6437:         @selected_sections = ($env{'request.course.sec'});
                   6438:     }
1.269     raeburn  6439:     my @selected_groups =
                   6440:         &Apache::loncommon::get_env_multiple('form.Group');
1.211     www      6441: 
                   6442:     my $pssymb='';
                   6443:     my $parmlev='';
1.446     bisitz   6444: 
1.211     www      6445:     unless ($env{'form.parmlev'}) {
                   6446:         $parmlev = 'map';
                   6447:     } else {
                   6448:         $parmlev = $env{'form.parmlev'};
                   6449:     }
                   6450: 
1.446     bisitz   6451:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 6452:                 \%mapp, \%symbp,\%maptitles,\%uris,
1.603     raeburn  6453:                 \%keyorder,\%defkeytype,$pssymb);
1.211     www      6454: 
1.374     albertel 6455:     if (grep {$_ eq 'all'} (@psprt)) {
1.481     amueller 6456:         @psprt = keys(%allparts);
1.374     albertel 6457:     }
1.211     www      6458: # Menu to select levels, etc
                   6459: 
1.456     bisitz   6460:     $r->print('<div class="LC_Box">');
1.445     neumanie 6461:     #$r->print('<h2 class="LC_hcell">Step 1</h2>');
1.452     bisitz   6462:     $r->print('<div>');
1.523     raeburn  6463:     $r->print(&Apache::lonhtmlcommon::start_pick_box(undef,'parmlevel'));
1.211     www      6464:     &levelmenu($r,\%alllevs,$parmlev);
1.610     raeburn  6465:     $r->print(&Apache::lonhtmlcommon::row_closure());
                   6466:     &mapmenu($r,\%allmaps,$pschp,\%maptitles,\%symbp,$parmlev);
1.447     bisitz   6467:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.445     neumanie 6468:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   6469:     $r->print('</div></div>');
1.446     bisitz   6470: 
1.456     bisitz   6471:     $r->print('<div class="LC_Box">');
1.452     bisitz   6472:     $r->print('<div>');
1.581     raeburn  6473:     &displaymenu($r,\%allparms,\@pscat,\%keyorder);
1.453     schualex 6474:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.446     bisitz   6475:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parts to View')));
1.553     raeburn  6476:     my $sectionselector = &sectionmenu(\@selected_sections);
                   6477:     my $groupselector = &groupmenu(\@selected_groups);
1.481     amueller 6478:     $r->print('<table>'.
1.553     raeburn  6479:               '<tr><th>'.&mt('Parts').'</th>');
                   6480:     if ($sectionselector) {
                   6481:         $r->print('<th>'.&mt('Section(s)').'</th>');
                   6482:     }
                   6483:     if ($groupselector) {
                   6484:         $r->print('<th>'.&mt('Group(s)').'</th>');
                   6485:     }
                   6486:     $r->print('</tr><tr><td>');
1.211     www      6487:     &partmenu($r,\%allparts,\@psprt);
1.553     raeburn  6488:     $r->print('</td>');
                   6489:     if ($sectionselector) { 
                   6490:         $r->print('<td>'.$sectionselector.'</td>');
                   6491:     }
                   6492:     if ($groupselector) {
                   6493:         $r->print('<td>'.$groupselector.'</td>');
                   6494:     }
                   6495:     $r->print('</tr></table>');
1.447     bisitz   6496:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.445     neumanie 6497:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   6498:     $r->print('</div></div>');
                   6499: 
1.456     bisitz   6500:     $r->print('<div class="LC_Box">');
1.452     bisitz   6501:     $r->print('<div>');
1.214     www      6502:     my $sortorder=$env{'form.sortorder'};
                   6503:     unless ($sortorder) { $sortorder='realmstudent'; }
1.612     raeburn  6504:     &sortmenu($r,$sortorder,'newoverview');
1.445     neumanie 6505:     $r->print('</div></div>');
1.446     bisitz   6506: 
1.214     www      6507:     $r->print('<p><input type="submit" name="dis" value="'.&mt('Display').'" /></p>');
1.446     bisitz   6508: 
1.211     www      6509: # Build the list data hash from the specified parms
                   6510: 
                   6511:     my $listdata;
                   6512:     %{$listdata}=();
                   6513: 
                   6514:     foreach my $cat (@pscat) {
1.269     raeburn  6515:         &secgroup_lister($cat,$pschp,$parmlev,$listdata,\@psprt,\@selected_sections,\%defkeytype,\%allmaps,\@ids,\%symbp);
                   6516:         &secgroup_lister($cat,$pschp,$parmlev,$listdata,\@psprt,\@selected_groups,\%defkeytype,\%allmaps,\@ids,\%symbp);
1.211     www      6517:     }
                   6518: 
1.212     www      6519:     if (($env{'form.store'}) || ($env{'form.dis'})) {
1.211     www      6520: 
1.481     amueller 6521:         if ($env{'form.store'}) { &storedata($r,$crs,$dom); }
1.211     www      6522: 
                   6523: # Read modified data
                   6524: 
1.481     amueller 6525:         my $resourcedata=&readdata($crs,$dom);
1.211     www      6526: 
                   6527: # List data
                   6528: 
1.608     raeburn  6529:         my $hash_for_realm;
                   6530:         if (($parmlev eq 'map') && (keys(%allmaps))) {
                   6531:             %{$hash_for_realm} = reverse(%allmaps);
                   6532:         } elsif (($parmlev eq 'full') && (keys(%symbp))) {
                   6533:             for (my $i=0; $i<@ids; $i++) {
                   6534:                 $hash_for_realm->{$symbp{$ids[$i]}} = $i;
                   6535:             }
                   6536:         }
                   6537:         &listdata($r,$resourcedata,$listdata,$sortorder,'newoverview',undef,$readonly,$parmlev,$hash_for_realm,$pschp);
1.568     raeburn  6538:     }
                   6539:     $r->print(&tableend());
                   6540:     unless ($readonly) {
                   6541:         $r->print( ((($env{'form.store'}) || ($env{'form.dis'}))?'<p><input type="submit" name="store" value="'.&mt('Save').'" /></p>':'') );
1.211     www      6542:     }
1.568     raeburn  6543:     $r->print('</form>');
1.507     www      6544:     &endSettingsScreen($r);
                   6545:     $r->print(&Apache::loncommon::end_page());
1.208     www      6546: }
                   6547: 
1.563     damieng  6548: # Fills $listdata with parameter information.
                   6549: # Keys use the format course id.[section id].part.name and course id.[section id].part.name.type.
                   6550: # The non-type value is always 1.
                   6551: #
                   6552: # @param {string} $cat - parameter name
1.566     damieng  6553: # @param {string} $pschp - selected map pc, or 'all'
1.563     damieng  6554: # @param {string} $parmlev - selected level value (full|map|general), or ''
                   6555: # @param {hash reference} $listdata - the parameter data that will be modified
                   6556: # @param {array reference} $psprt - selected parts
                   6557: # @param {array reference} $selections - selected sections
                   6558: # @param {hash reference} $defkeytype - hash parameter name -> parameter type
1.566     damieng  6559: # @param {hash reference} $allmaps - hash map pc -> map src
                   6560: # @param {array reference} $ids - resource and map ids
                   6561: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' or resource symb
1.269     raeburn  6562: sub secgroup_lister {
                   6563:     my ($cat,$pschp,$parmlev,$listdata,$psprt,$selections,$defkeytype,$allmaps,$ids,$symbp) = @_;
                   6564:     foreach my $item (@{$selections}) {
                   6565:         foreach my $part (@{$psprt}) {
                   6566:             my $rootparmkey=$env{'request.course.id'};
                   6567:             if (($item ne 'all') && ($item ne 'none') && ($item)) {
                   6568:                 $rootparmkey.='.['.$item.']';
                   6569:             }
                   6570:             if ($parmlev eq 'general') {
                   6571: # course-level parameter
                   6572:                 my $newparmkey=$rootparmkey.'.'.$part.'.'.$cat;
                   6573:                 $$listdata{$newparmkey}=1;
                   6574:                 $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6575:             } elsif ($parmlev eq 'map') {
                   6576: # map-level parameter
1.548     raeburn  6577:                 foreach my $mapid (keys(%{$allmaps})) {
1.269     raeburn  6578:                     if (($pschp ne 'all') && ($pschp ne $mapid)) { next; }
                   6579:                     my $newparmkey=$rootparmkey.'.'.$$allmaps{$mapid}.'___(all).'.$part.'.'.$cat;
                   6580:                     $$listdata{$newparmkey}=1;
                   6581:                     $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6582:                 }
                   6583:             } else {
                   6584: # resource-level parameter
                   6585:                 foreach my $rid (@{$ids}) {
                   6586:                     my ($map,$resid,$url)=&Apache::lonnet::decode_symb($$symbp{$rid});
                   6587:                     if (($pschp ne 'all') && ($$allmaps{$pschp} ne $map)) { next; }
                   6588:                     my $newparmkey=$rootparmkey.'.'.$$symbp{$rid}.'.'.$part.'.'.$cat;
                   6589:                     $$listdata{$newparmkey}=1;
                   6590:                     $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6591:                 }
                   6592:             }
                   6593:         }
                   6594:     }
                   6595: }
                   6596: 
1.563     damieng  6597: # UI to edit parameter settings starting with a list of all existing parameters.
                   6598: # (called by setoverview action)
                   6599: #
                   6600: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      6601: sub overview {
1.568     raeburn  6602:     my ($r,$parm_permission) = @_;
1.208     www      6603:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6604:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6605:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.568     raeburn  6606:     my $readonly = 1;
                   6607:     if ($parm_permission->{'edit'}) {
                   6608:         undef($readonly);
                   6609:     }
1.549     raeburn  6610:     my $js = '<script type="text/javascript">'."\n".
                   6611:              '// <![CDATA['."\n".
                   6612:              &toggleparmtextbox_js()."\n".
                   6613:              &validateparms_js()."\n".
                   6614:              &ipacc_boxes_js()."\n".
1.622     raeburn  6615:              &grace_js()."\n".
1.558     raeburn  6616:              &done_proctor_js()."\n".
1.588     raeburn  6617:              &deeplink_js()."\n".
1.549     raeburn  6618:              '// ]]>'."\n".
                   6619:              '</script>'."\n";
1.414     droeschl 6620:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview',
1.473     amueller 6621:     text=>"Overview Mode"});
1.549     raeburn  6622:     my %loaditems = (
                   6623:                       'onload'   => "showHideLenient();",
                   6624:                     );
                   6625: 
                   6626:     my $start_page=&Apache::loncommon::start_page('Modify Parameters',$js,{'add_entries' => \%loaditems,});
1.298     albertel 6627:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview');
1.507     www      6628:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6629:     &startSettingsScreen($r,'parmset',$crstype);
1.549     raeburn  6630:     $r->print('<form method="post" action="/adm/parmset?action=setoverview" name="parmform" onsubmit="return validateParms();">');
1.507     www      6631: 
1.208     www      6632: # Store modified
                   6633: 
1.568     raeburn  6634:     unless ($readonly) {
                   6635:         &storedata($r,$crs,$dom);
                   6636:     }
1.208     www      6637: 
                   6638: # Read modified data
                   6639: 
1.552     raeburn  6640:     my ($resourcedata,$classlist)=&readdata($crs,$dom);
1.208     www      6641: 
1.214     www      6642: 
                   6643:     my $sortorder=$env{'form.sortorder'};
                   6644:     unless ($sortorder) { $sortorder='realmstudent'; }
1.608     raeburn  6645:     &sortmenu($r,$sortorder,'overview');
1.214     www      6646: 
1.568     raeburn  6647:     my $submitbutton = '<input type="submit" value="'.&mt('Save').'" />';
                   6648: 
                   6649:     if ($readonly) {
                   6650:         $r->print('<p>'.$submitbutton.'</p>');
                   6651:     }
                   6652: 
1.208     www      6653: # List data
                   6654: 
1.568     raeburn  6655:     my $foundkeys=&listdata($r,$resourcedata,$resourcedata,$sortorder,'overview',$classlist,$readonly);
                   6656:     $r->print(&tableend().'<p>');
                   6657:     if ($foundkeys) {
                   6658:         unless ($readonly) {
                   6659:             $r->print('<p>'.$submitbutton.'</p>');
                   6660:         }
                   6661:     } else {
                   6662:         $r->print('<p class="LC_info">'.&mt('There are no parameters.').'</p>');
                   6663:     }
                   6664:     $r->print('</form>'.&Apache::loncommon::end_page());
1.120     www      6665: }
1.121     www      6666: 
1.560     damieng  6667: # Unused sub.
1.563     damieng  6668: #
                   6669: # @param {Apache2::RequestRec} $r - the Apache request
1.333     albertel 6670: sub clean_parameters {
                   6671:     my ($r) = @_;
                   6672:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6673:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
                   6674: 
1.414     droeschl 6675:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=cleanparameters',
1.473     amueller 6676:         text=>"Clean Parameters"});
1.333     albertel 6677:     my $start_page=&Apache::loncommon::start_page('Clean Parameters');
                   6678:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Clean');
                   6679:     $r->print(<<ENDOVER);
                   6680: $start_page
                   6681: $breadcrumbs
                   6682: <form method="post" action="/adm/parmset?action=cleanparameters" name="parmform">
                   6683: ENDOVER
                   6684: # Store modified
                   6685: 
                   6686:     &storedata($r,$crs,$dom);
                   6687: 
                   6688: # Read modified data
                   6689: 
                   6690:     my $resourcedata=&readdata($crs,$dom);
                   6691: 
                   6692: # List data
                   6693: 
                   6694:     $r->print('<h3>'.
1.473     amueller 6695:           &mt('These parameters refer to resources that do not exist.').
                   6696:           '</h3>'.
                   6697:           '<input type="submit" value="'.&mt('Delete Selected').'" />'.'<br />'.
                   6698:           '<br />');
1.333     albertel 6699:     $r->print(&Apache::loncommon::start_data_table().
1.473     amueller 6700:           '<tr>'.
                   6701:           '<th>'.&mt('Delete').'</th>'.
                   6702:           '<th>'.&mt('Parameter').'</th>'.
                   6703:           '</tr>');
1.333     albertel 6704:     foreach my $thiskey (sort(keys(%{$resourcedata}))) {
1.560     damieng  6705:         next if (!exists($resourcedata->{$thiskey.'.type'})
                   6706:             && $thiskey=~/\.type$/);
                   6707:         my %data = &parse_key($thiskey);
                   6708:         if (1) { #exists($data{'realm_exists'})
                   6709:             #&& !$data{'realm_exists'}) {
                   6710:             $r->print(&Apache::loncommon::start_data_table_row().
                   6711:                 '<tr>'.
                   6712:                 '<td><input type="checkbox" name="del_'.$thiskey.'" /></td>'              );
                   6713: 
                   6714:             $r->print('<td>');
                   6715:             my $display_value = $resourcedata->{$thiskey};
                   6716:             if (&isdateparm($resourcedata->{$thiskey.'.type'})) {
                   6717:             $display_value =
                   6718:                 &Apache::lonlocal::locallocaltime($display_value);
                   6719:             }
1.470     raeburn  6720:             my $parmitem = &standard_parameter_names($data{'parameter_name'});
                   6721:             $parmitem = &mt($parmitem);
1.560     damieng  6722:             $r->print(&mt('Parameter: "[_1]" with value: "[_2]"',
                   6723:                 $parmitem,$resourcedata->{$thiskey}));
                   6724:             $r->print('<br />');
                   6725:             if ($data{'scope_type'} eq 'all') {
                   6726:                 $r->print(&mt('All users'));
                   6727:             } elsif ($data{'scope_type'} eq 'user') {
                   6728:                 $r->print(&mt('User: [_1]',join(':',@{$data{'scope'}})));
1.581     raeburn  6729:             } elsif ($data{'scope_type'} eq 'secgroup') {
                   6730:                 $r->print(&mt('Group/Section: [_1]',$data{'scope'}));
1.560     damieng  6731:             }
                   6732:             $r->print('<br />');
                   6733:             if ($data{'realm_type'} eq 'all') {
                   6734:                 $r->print(&mt('All Resources'));
                   6735:             } elsif ($data{'realm_type'} eq 'folder') {
                   6736:                 $r->print(&mt('Folder: [_1]'),$data{'realm'});
                   6737:             } elsif ($data{'realm_type'} eq 'symb') {
                   6738:             my ($map,$resid,$url) =
                   6739:                 &Apache::lonnet::decode_symb($data{'realm'});
                   6740:             $r->print(&mt('Resource: [_1]with ID: [_2]in folder [_3]',
                   6741:                         $url.' <br />&nbsp;&nbsp;&nbsp;',
                   6742:                         $resid.' <br />&nbsp;&nbsp;&nbsp;',$map));
                   6743:             }
                   6744:             $r->print(' <br />&nbsp;&nbsp;&nbsp;'.&mt('Part: [_1]',$data{'parameter_part'}));
                   6745:             $r->print('</td></tr>');
                   6746: 
1.473     amueller 6747:         }
1.333     albertel 6748:     }
                   6749:     $r->print(&Apache::loncommon::end_data_table().'<p>'.
1.473     amueller 6750:           '<input type="submit" value="'.&mt('Delete Selected').'" />'.
1.507     www      6751:           '</p></form>');
                   6752:     &endSettingsScreen($r);
                   6753:     $r->print(&Apache::loncommon::end_page());
1.333     albertel 6754: }
                   6755: 
1.563     damieng  6756: # UI to shift all dates (called by dateshift1 action).
                   6757: # Used by overview mode.
                   6758: #
                   6759: # @param {Apache2::RequestRec} $r - the Apache request
1.390     www      6760: sub date_shift_one {
                   6761:     my ($r) = @_;
                   6762:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6763:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6764:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.594     raeburn  6765:     my $sec = $env{'request.course.sec'};
1.414     droeschl 6766:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'},
1.473     amueller 6767:         text=>"Shifting Dates"});
1.594     raeburn  6768:     my $submit_text = &mt('Shift all dates accordingly');
                   6769:     if ($sec ne '') {
1.595     raeburn  6770:         my @groups;
                   6771:         if ($env{'request.course.groups'} ne '') {
                   6772:             @groups = split(/:/,$env{'request.course.groups'});
                   6773:         }
                   6774:         if (@groups) {
                   6775:             $submit_text = &mt("Shift dates set just for your section/group(s), accordingly");
                   6776:         } else {
                   6777:             $submit_text = &mt("Shift dates set just for your section, accordingly");
                   6778:         }
1.594     raeburn  6779:     }
1.390     www      6780:     my $start_page=&Apache::loncommon::start_page('Shift Dates');
                   6781:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
1.507     www      6782:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6783:     &startSettingsScreen($r,'parmset',$crstype);
1.538     bisitz   6784:     $r->print('<form name="shiftform" method="post" action="">'.
1.390     www      6785:               '<table><tr><td>'.&mt('Currently set date:').'</td><td>'.
                   6786:               &Apache::lonlocal::locallocaltime($env{'form.timebase'}).'</td></tr>'.
                   6787:               '<tr><td>'.&mt('Shifted date:').'</td><td>'.
1.541     bisitz   6788:                     &Apache::lonhtmlcommon::date_setter('shiftform',
1.390     www      6789:                                                         'timeshifted',
                   6790:                                                         $env{'form.timebase'},,
                   6791:                                                         '').
                   6792:               '</td></tr></table>'.
                   6793:               '<input type="hidden" name="action" value="dateshift2" />'.
                   6794:               '<input type="hidden" name="timebase" value="'.$env{'form.timebase'}.'" />'.
1.594     raeburn  6795:               '<input type="submit" value="'.$submit_text.'" /></form>');
1.507     www      6796:     &endSettingsScreen($r);
1.390     www      6797:     $r->print(&Apache::loncommon::end_page());
                   6798: }
                   6799: 
1.563     damieng  6800: # UI to shift all dates (second form).
                   6801: #
                   6802: # @param {Apache2::RequestRec} $r - the Apache request
1.390     www      6803: sub date_shift_two {
                   6804:     my ($r) = @_;
                   6805:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6806:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.594     raeburn  6807:     my $sec = $env{'request.course.sec'};
1.531     raeburn  6808:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.414     droeschl 6809:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'},
1.473     amueller 6810:         text=>"Shifting Dates"});
1.390     www      6811:     my $start_page=&Apache::loncommon::start_page('Shift Dates');
                   6812:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
1.507     www      6813:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6814:     &startSettingsScreen($r,'parmset',$crstype);
1.390     www      6815:     my $timeshifted=&Apache::lonhtmlcommon::get_date_from_form('timeshifted');
1.594     raeburn  6816:     $r->print('<h2>'.&mt('Shift Dates').'</h2>');
                   6817:     if ($sec ne '') {
1.595     raeburn  6818:         my @groups;
                   6819:         if ($env{'request.course.groups'} ne '') {
                   6820:             @groups = split(/:/,$env{'request.course.groups'});
                   6821:         }
                   6822:         if (@groups) {
                   6823:             $r->print('<p>'.
                   6824:                       &mt("Shift dates set just for your section/group(s), such that [_1] becomes [_2]",
                   6825:                           &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6826:                           &Apache::lonlocal::locallocaltime($timeshifted)).
                   6827:                       '</p>');
                   6828:         } else {
                   6829:             $r->print('<p>'.
                   6830:                       &mt("Shift dates set just for your section, such that [_1] becomes [_2]",
                   6831:                           &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6832:                           &Apache::lonlocal::locallocaltime($timeshifted)).
                   6833:                       '</p>');
                   6834:         }
1.594     raeburn  6835:     } else {
                   6836:         $r->print('<p>'.&mt('Shifting all dates such that [_1] becomes [_2]',
                   6837:                             &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6838:                             &Apache::lonlocal::locallocaltime($timeshifted)).
                   6839:                   '</p>');
                   6840:     }
1.390     www      6841:     my $delta=$timeshifted-$env{'form.timebase'};
1.594     raeburn  6842:     my $numchanges = 0;
                   6843:     my $result = &dateshift($delta,\$numchanges);
                   6844:     if ($result eq 'ok') {
                   6845:         $r->print(
                   6846:             &Apache::lonhtmlcommon::confirm_success(&mt('Completed shifting of [quant,_1,date setting]',
                   6847:                                                     $numchanges)));
                   6848:     } elsif ($result eq 'con_delayed') {
                   6849:         $r->print(
                   6850:             &Apache::lonhtmlcommon::confirm_success(&mt('Queued shifting of [quant,_1,date setting]',
                   6851:                                                         $numchanges)));
                   6852:     } else {
                   6853:         $r->print(
                   6854:             &Apache::lonhtmlcommon::confirm_success(&mt('An error occurred attempting to shift dates'),1));
                   6855:     }
1.543     bisitz   6856:     $r->print(
                   6857:         '<br /><br />'.
                   6858:         &Apache::lonhtmlcommon::actionbox(
                   6859:             ['<a href="/adm/parmset">'.&mt('Content and Problem Settings').'</a>']));
1.507     www      6860:     &endSettingsScreen($r);
1.390     www      6861:     $r->print(&Apache::loncommon::end_page());
                   6862: }
                   6863: 
1.563     damieng  6864: # Returns the different components of a resourcedata key.
                   6865: # Keys: scope_type, scope, realm_type, realm, realm_title,
                   6866: #       realm_exists, parameter_part, parameter_name.
                   6867: # Was used by clean_parameters (which is unused).
                   6868: #
                   6869: # @param {string} $key - the parameter key
                   6870: # @returns {hash}
1.333     albertel 6871: sub parse_key {
                   6872:     my ($key) = @_;
                   6873:     my %data;
                   6874:     my ($middle,$part,$name)=
1.572     damieng  6875:     ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.333     albertel 6876:     $data{'scope_type'} = 'all';
                   6877:     if ($middle=~/^\[(.*)\]/) {
1.560     damieng  6878:         $data{'scope'} = $1;
                   6879:         if ($data{'scope'}=~/^useropt\:($match_username)\:($match_domain)/) {
                   6880:             $data{'scope_type'} = 'user';
                   6881:             $data{'scope'} = [$1,$2];
                   6882:         } else {
1.581     raeburn  6883:             $data{'scope_type'} = 'secgroup';
1.560     damieng  6884:         }
                   6885:         $middle=~s/^\[(.*)\]//;
1.333     albertel 6886:     }
                   6887:     $middle=~s/\.+$//;
                   6888:     $middle=~s/^\.+//;
                   6889:     $data{'realm_type'}='all';
                   6890:     if ($middle=~/^(.+)\_\_\_\(all\)$/) {
1.560     damieng  6891:         $data{'realm'} = $1;
                   6892:         $data{'realm_type'} = 'folder';
                   6893:         $data{'realm_title'} = &Apache::lonnet::gettitle($data{'realm'});
                   6894:         ($data{'realm_exists'}) = &Apache::lonnet::is_on_map($data{'realm'});
1.333     albertel 6895:     } elsif ($middle) {
1.560     damieng  6896:         $data{'realm'} = $middle;
                   6897:         $data{'realm_type'} = 'symb';
                   6898:         $data{'realm_title'} = &Apache::lonnet::gettitle($data{'realm'});
                   6899:         my ($map,$resid,$url) = &Apache::lonnet::decode_symb($data{'realm'});
                   6900:         $data{'realm_exists'} = &Apache::lonnet::symbverify($data{'realm'},$url);
1.333     albertel 6901:     }
1.446     bisitz   6902: 
1.333     albertel 6903:     $data{'parameter_part'} = $part;
                   6904:     $data{'parameter_name'} = $name;
                   6905: 
                   6906:     return %data;
                   6907: }
                   6908: 
1.239     raeburn  6909: 
1.563     damieng  6910: # Calls loncommon::start_page with the "Settings" title.
1.416     jms      6911: sub header {
1.507     www      6912:     return &Apache::loncommon::start_page('Settings');
1.416     jms      6913: }
1.193     albertel 6914: 
                   6915: 
                   6916: 
1.560     damieng  6917: ##################################################
                   6918: # MAIN MENU
                   6919: ##################################################
                   6920: 
1.563     damieng  6921: # Content and problem settings main menu.
                   6922: #
                   6923: # @param {Apache2::RequestRec} $r - the Apache request
                   6924: # @param {boolean} $parm_permission - true if the user has permission to edit the current course or section
1.193     albertel 6925: sub print_main_menu {
                   6926:     my ($r,$parm_permission)=@_;
                   6927:     #
1.414     droeschl 6928:     $r->print(&header());
1.507     www      6929:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Content and Problem Settings'));
1.531     raeburn  6930:     my $crstype = &Apache::loncommon::course_type();
                   6931:     my $lc_crstype = lc($crstype);
                   6932: 
                   6933:     &startSettingsScreen($r,'parmset',$crstype);
1.193     albertel 6934:     $r->print(<<ENDMAINFORMHEAD);
                   6935: <form method="post" enctype="multipart/form-data"
                   6936:       action="/adm/parmset" name="studentform">
                   6937: ENDMAINFORMHEAD
                   6938: #
1.195     albertel 6939:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   6940:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
1.268     albertel 6941:     my $vgr  = &Apache::lonnet::allowed('vgr',$env{'request.course.id'});
1.366     albertel 6942:     my $mgr  = &Apache::lonnet::allowed('mgr',$env{'request.course.id'});
1.520     raeburn  6943:     my $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'});
1.568     raeburn  6944:     my $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'});
                   6945:     my $vpa = &Apache::lonnet::allowed('vpa',$env{'request.course.id'});
1.520     raeburn  6946:     if ((!$dcm) && ($env{'request.course.sec'} ne '')) {
                   6947:         $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'}.
                   6948:                                         '/'.$env{'request.course.sec'});
                   6949:     }
1.568     raeburn  6950:     if ((!$vcb) && ($env{'request.course.sec'} ne '')) {
                   6951:         $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'}.
                   6952:                                         '/'.$env{'request.course.sec'});
                   6953:     }
                   6954:     my (%linktext,%linktitle,%url);
                   6955:     if ($parm_permission->{'edit'}) {
                   6956:         %linktext = (
                   6957:                      newoverview     => 'Edit Resource Parameters - Overview Mode',
                   6958:                      settable        => 'Edit Resource Parameters - Table Mode',
                   6959:                      setoverview     => 'Modify Resource Parameters - Overview Mode',
                   6960:                     );
                   6961:         %linktitle = (
                   6962:                      newoverview     => 'Set/Modify resource parameters in overview mode.',
                   6963:                      settable        => 'Set/Modify resource parameters in table mode.',
                   6964:                      setoverview     => 'Set/Modify existing resource parameters in overview mode.',
                   6965:                      );
                   6966:     } else {
                   6967:         %linktext = (
                   6968:                      newoverview     => 'View Resource Parameters - Overview Mode',
                   6969:                      settable        => 'View Resource Parameters - Table Mode',
                   6970:                      setoverview     => 'View Resource Parameters - Overview Mode',
                   6971:                    );
                   6972:         %linktitle = (
                   6973:                      newoverview     => 'Display resource parameters in overview mode.',
                   6974:                      settable        => 'Display resource parameters in table mode.',
                   6975:                      setoverview     => 'Display existing resource parameters in overview mode.',
                   6976:                      );
                   6977:     }
                   6978:     if ($mgr) {
                   6979:         $linktext{'resettimes'} = 'Reset Student Access Times';
                   6980:         $linktitle{'resettimes'} = "Reset access times for folders/maps, resources or the $lc_crstype.";
                   6981:         $url{'resettimes'} = '/adm/helper/resettimes.helper';
                   6982:     } elsif ($vgr) {
                   6983:         $linktext{'resettimes'} = 'Display Student Access Times',
                   6984:         $linktitle{'resettimes'} = "Display access times for folders/maps, resources or the $lc_crstype.",
                   6985:         $url{'resettimes'} = '/adm/accesstimes';
                   6986:     }
1.193     albertel 6987:     my @menu =
1.507     www      6988:         ( { categorytitle=>"Content Settings for this $crstype",
1.473     amueller 6989:         items => [
                   6990:           { linktext => 'Portfolio Metadata',
                   6991:             url => '/adm/parmset?action=setrestrictmeta',
1.568     raeburn  6992:             permission => $parm_permission->{'setrestrictmeta'},
1.477     raeburn  6993:             linktitle => "Restrict metadata for this $lc_crstype." ,
1.473     amueller 6994:             icon =>'contact-new.png'   ,
                   6995:             },
1.568     raeburn  6996:           { linktext => $linktext{'resettimes'},
                   6997:             url => $url{'resettimes'},
                   6998:             permission => ($vgr || $mgr),
                   6999:             linktitle => $linktitle{'resettimes'},
                   7000:             icon => 'start-here.png',
1.473     amueller 7001:             },
1.520     raeburn  7002:           { linktext => 'Blocking Communication/Resource Access',
                   7003:             url => '/adm/setblock',
1.568     raeburn  7004:             permission => ($vcb || $dcm),
1.520     raeburn  7005:             linktitle => 'Configure blocking of communication/collaboration and access to resources during an exam',
                   7006:             icon => 'comblock.png',
                   7007:             },
1.473     amueller 7008:           { linktext => 'Set Parameter Setting Default Actions',
                   7009:             url => '/adm/parmset?action=setdefaults',
1.568     raeburn  7010:             permission => $parm_permission->{'setdefaults'},
1.473     amueller 7011:             linktitle =>'Set default actions for parameters.'  ,
                   7012:             icon => 'folder-new.png'  ,
                   7013:             }]},
                   7014:       { categorytitle => 'New and Existing Parameter Settings for Resources',
                   7015:         items => [
                   7016:           { linktext => 'Edit Resource Parameters - Helper Mode',
                   7017:             url => '/adm/helper/parameter.helper',
1.568     raeburn  7018:             permission => $parm_permission->{'helper'},
1.473     amueller 7019:             linktitle =>'Set/Modify resource parameters in helper mode.'  ,
                   7020:             icon => 'dialog-information.png'  ,
                   7021:             #help => 'Parameter_Helper',
                   7022:             },
1.568     raeburn  7023:           { linktext => $linktext{'newoverview'},
1.473     amueller 7024:             url => '/adm/parmset?action=newoverview',
1.568     raeburn  7025:             permission => $parm_permission->{'newoverview'},
                   7026:             linktitle => $linktitle{'newoverview'},
                   7027:             icon => 'edit-find.png',
1.473     amueller 7028:             #help => 'Parameter_Overview',
                   7029:             },
1.568     raeburn  7030:           { linktext => $linktext{'settable'},
1.473     amueller 7031:             url => '/adm/parmset?action=settable',
1.568     raeburn  7032:             permission => $parm_permission->{'settable'},
                   7033:             linktitle => $linktitle{'settable'},
                   7034:             icon => 'edit-copy.png',
1.473     amueller 7035:             #help => 'Table_Mode',
                   7036:             }]},
1.417     droeschl 7037:            { categorytitle => 'Existing Parameter Settings for Resources',
1.473     amueller 7038:          items => [
1.570     raeburn  7039:           { linktext => $linktext{'setoverview'},
1.473     amueller 7040:             url => '/adm/parmset?action=setoverview',
1.568     raeburn  7041:             permission => $parm_permission->{'setoverview'},
                   7042:             linktitle => $linktitle{'setoverview'},
                   7043:             icon => 'preferences-desktop-wallpaper.png',
1.473     amueller 7044:             #help => 'Parameter_Overview',
                   7045:             },
                   7046:           { linktext => 'Change Log',
                   7047:             url => '/adm/parmset?action=parameterchangelog',
1.568     raeburn  7048:             permission => $parm_permission->{'parameterchangelog'},
1.477     raeburn  7049:             linktitle =>"View parameter and $lc_crstype blog posting/user notification change log."  ,
1.487     wenzelju 7050:             icon => 'document-properties.png',
1.473     amueller 7051:             }]}
1.193     albertel 7052:           );
1.414     droeschl 7053:     $r->print(&Apache::lonhtmlcommon::generate_menu(@menu));
1.539     raeburn  7054:     $r->print('</form>');
1.507     www      7055:     &endSettingsScreen($r);
1.539     raeburn  7056:     $r->print(&Apache::loncommon::end_page());
1.193     albertel 7057:     return;
                   7058: }
1.414     droeschl 7059: 
1.416     jms      7060: 
                   7061: 
1.560     damieng  7062: ##################################################
                   7063: # PORTFOLIO METADATA
                   7064: ##################################################
                   7065: 
1.563     damieng  7066: # Prints HTML to edit an item of portfolio metadata. The HTML contains several td elements (no tr).
                   7067: # It looks like field titles are not localized.
                   7068: #
                   7069: # @param {Apache2::RequestRec} $r - the Apache request
                   7070: # @param {string} $field_name - metadata field name
                   7071: # @param {string} $field_text - metadata field title, in English unless manually added
                   7072: # @param {boolean} $added_flag - true if the field was manually added
1.252     banghart 7073: sub output_row {
1.347     banghart 7074:     my ($r, $field_name, $field_text, $added_flag) = @_;
1.252     banghart 7075:     my $output;
1.263     banghart 7076:     my $options=$env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.options'};
                   7077:     my $values=$env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.values'};
1.337     banghart 7078:     if (!defined($options)) {
1.254     banghart 7079:         $options = 'active,stuadd';
1.261     banghart 7080:         $values = '';
1.252     banghart 7081:     }
1.337     banghart 7082:     if (!($options =~ /deleted/)) {
                   7083:         my @options= ( ['active', 'Show to student'],
1.418     schafran 7084:                     ['stuadd', 'Provide text area for students to type metadata'],
1.351     banghart 7085:                     ['choices','Provide choices for students to select from']);
1.473     amueller 7086: #           ['onlyone','Student may select only one choice']);
1.337     banghart 7087:         if ($added_flag) {
                   7088:             push @options,['deleted', 'Delete Metadata Field'];
                   7089:         }
1.351     banghart 7090:        $output = &Apache::loncommon::start_data_table_row();
1.451     bisitz   7091:         $output .= '<td><strong>'.$field_text.':</strong></td>';
1.351     banghart 7092:         $output .= &Apache::loncommon::end_data_table_row();
1.337     banghart 7093:         foreach my $opt (@options) {
1.560     damieng  7094:             my $checked = ($options =~ m/$opt->[0]/) ? ' checked="checked" ' : '' ;
                   7095:             $output .= &Apache::loncommon::continue_data_table_row();
                   7096:             $output .= '<td>'.('&nbsp;' x 5).'<label>
                   7097:                     <input type="checkbox" name="'.
                   7098:                     $field_name.'_'.$opt->[0].'" value="yes"'.$checked.' />'.
                   7099:                     &mt($opt->[1]).'</label></td>';
                   7100:             $output .= &Apache::loncommon::end_data_table_row();
                   7101:         }
1.351     banghart 7102:         $output .= &Apache::loncommon::continue_data_table_row();
1.451     bisitz   7103:         $output .= '<td>'.('&nbsp;' x 10).'<input name="'.$field_name.'_values" type="text" value="'.$values.'" size="80" /></td>';
1.351     banghart 7104:         $output .= &Apache::loncommon::end_data_table_row();
                   7105:         my $multiple_checked;
                   7106:         my $single_checked;
                   7107:         if ($options =~ m/onlyone/) {
1.422     bisitz   7108:             $multiple_checked = '';
1.423     bisitz   7109:             $single_checked = ' checked="checked"';
1.351     banghart 7110:         } else {
1.423     bisitz   7111:             $multiple_checked = ' checked="checked"';
1.422     bisitz   7112:             $single_checked = '';
1.351     banghart 7113:         }
1.560     damieng  7114:         $output .= &Apache::loncommon::continue_data_table_row();
                   7115:         $output .= '<td>'.('&nbsp;' x 10).'
                   7116:                     <input type="radio" name="'.$field_name.'_onlyone" value="multiple"'.$multiple_checked .' />
                   7117:                     '.&mt('Student may select multiple choices from list').'</td>';
                   7118:         $output .= &Apache::loncommon::end_data_table_row();
                   7119:         $output .= &Apache::loncommon::continue_data_table_row();
                   7120:         $output .= '<td>'.('&nbsp;' x 10).'
                   7121:                     <input type="radio" name="'.$field_name.'_onlyone"  value="single"'.$single_checked.' />
                   7122:                     '.&mt('Student may select only one choice from list').'</td>';
                   7123:         $output .= &Apache::loncommon::end_data_table_row();
1.252     banghart 7124:     }
                   7125:     return ($output);
                   7126: }
1.416     jms      7127: 
                   7128: 
1.560     damieng  7129: # UI to order portfolio metadata fields.
1.563     damieng  7130: # Currently useless because addmetafield does not work.
                   7131: #
                   7132: # @param {Apache2::RequestRec} $r - the Apache request
1.340     banghart 7133: sub order_meta_fields {
                   7134:     my ($r)=@_;
                   7135:     my $idx = 1;
                   7136:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7137:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7138:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};;
1.341     banghart 7139:     $r->print(&Apache::loncommon::start_page('Order Metadata Fields'));
1.560     damieng  7140:     &Apache::lonhtmlcommon::add_breadcrumb(
                   7141:         {href=>'/adm/parmset?action=addmetadata',
1.473     amueller 7142:         text=>"Add Metadata Field"});
1.560     damieng  7143:     &Apache::lonhtmlcommon::add_breadcrumb(
                   7144:         {href=>"/adm/parmset?action=setrestrictmeta",
                   7145:         text=>"Restrict Metadata"},
                   7146:         {text=>"Order Metadata"});
1.345     banghart 7147:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Order Metadata'));
1.531     raeburn  7148:     &startSettingsScreen($r,'parmset',$crstype);
1.340     banghart 7149:     if ($env{'form.storeorder'}) {
                   7150:         my $newpos = $env{'form.newpos'} - 1;
                   7151:         my $currentpos = $env{'form.currentpos'} - 1;
                   7152:         my @neworder = ();
1.548     raeburn  7153:         my @oldorder = split(/,/,$env{'course.'.$env{'request.course.id'}.'.metadata.addedorder'});
1.340     banghart 7154:         my $i;
1.341     banghart 7155:         if ($newpos > $currentpos) {
1.340     banghart 7156:         # moving stuff up
                   7157:             for ($i=0;$i<$currentpos;$i++) {
1.560     damieng  7158:                 $neworder[$i]=$oldorder[$i];
1.340     banghart 7159:             }
                   7160:             for ($i=$currentpos;$i<$newpos;$i++) {
1.560     damieng  7161:                 $neworder[$i]=$oldorder[$i+1];
1.340     banghart 7162:             }
                   7163:             $neworder[$newpos]=$oldorder[$currentpos];
                   7164:             for ($i=$newpos+1;$i<=$#oldorder;$i++) {
1.560     damieng  7165:                 $neworder[$i]=$oldorder[$i];
1.340     banghart 7166:             }
                   7167:         } else {
                   7168:         # moving stuff down
1.473     amueller 7169:             for ($i=0;$i<$newpos;$i++) {
                   7170:                 $neworder[$i]=$oldorder[$i];
                   7171:             }
                   7172:             $neworder[$newpos]=$oldorder[$currentpos];
                   7173:             for ($i=$newpos+1;$i<$currentpos+1;$i++) {
                   7174:                 $neworder[$i]=$oldorder[$i-1];
                   7175:             }
                   7176:             for ($i=$currentpos+1;$i<=$#oldorder;$i++) {
                   7177:                 $neworder[$i]=$oldorder[$i];
                   7178:             }
1.340     banghart 7179:         }
1.560     damieng  7180:         my $ordered_fields = join ",", @neworder;
1.343     banghart 7181:         my $put_result = &Apache::lonnet::put('environment',
1.560     damieng  7182:                         {'metadata.addedorder'=>$ordered_fields},$dom,$crs);
                   7183:         &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.metadata.addedorder' => $ordered_fields});
1.340     banghart 7184:     }
1.357     raeburn  7185:     my $fields = &get_added_meta_fieldnames($env{'request.course.id'});
1.341     banghart 7186:     my $ordered_fields;
1.548     raeburn  7187:     my @fields_in_order = split(/,/,$env{'course.'.$env{'request.course.id'}.'.metadata.addedorder'});
1.340     banghart 7188:     if (!@fields_in_order) {
                   7189:         # no order found, pick sorted order then create metadata.addedorder key.
1.548     raeburn  7190:         foreach my $key (sort(keys(%$fields))) {
1.340     banghart 7191:             push @fields_in_order, $key;
1.341     banghart 7192:             $ordered_fields = join ",", @fields_in_order;
1.340     banghart 7193:         }
1.341     banghart 7194:         my $put_result = &Apache::lonnet::put('environment',
1.446     bisitz   7195:                             {'metadata.addedorder'=>$ordered_fields},$dom,$crs);
                   7196:     }
1.340     banghart 7197:     $r->print('<table>');
                   7198:     my $num_fields = scalar(@fields_in_order);
                   7199:     foreach my $key (@fields_in_order) {
                   7200:         $r->print('<tr><td>');
                   7201:         $r->print('<form method="post" action="">');
1.537     bisitz   7202:         $r->print('<select name="newpos" onchange="this.form.submit()">');
1.340     banghart 7203:         for (my $i = 1;$i le $num_fields;$i ++) {
                   7204:             if ($i eq $idx) {
                   7205:                 $r->print('<option value="'.$i.'"  SELECTED>('.$i.')</option>');
                   7206:             } else {
                   7207:                 $r->print('<option value="'.$i.'">'.$i.'</option>');
                   7208:             }
                   7209:         }
                   7210:         $r->print('</select></td><td>');
                   7211:         $r->print('<input type="hidden" name="currentpos" value="'.$idx.'" />');
                   7212:         $r->print('<input type="hidden" name="storeorder" value="true" />');
                   7213:         $r->print('</form>');
                   7214:         $r->print($$fields{$key}.'</td></tr>');
                   7215:         $idx ++;
                   7216:     }
                   7217:     $r->print('</table>');
1.507     www      7218:     &endSettingsScreen($r);
1.340     banghart 7219:     return 'ok';
                   7220: }
1.416     jms      7221: 
                   7222: 
1.563     damieng  7223: # Returns HTML with a Continue button redirecting to the initial portfolio metadata screen.
                   7224: # @returns {string}
1.359     banghart 7225: sub continue {
                   7226:     my $output;
                   7227:     $output .= '<form action="" method="post">';
                   7228:     $output .= '<input type="hidden" name="action" value="setrestrictmeta" />';
1.586     raeburn  7229:     $output .= '<input type="submit" value="'.&mt('Continue').'" />';
1.359     banghart 7230:     return ($output);
                   7231: }
1.416     jms      7232: 
                   7233: 
1.563     damieng  7234: # UI to add a metadata field.
                   7235: # Currenly does not work because of an HTML error (the field is not visible).
                   7236: #
                   7237: # @param {Apache2::RequestRec} $r - the Apache request
1.334     banghart 7238: sub addmetafield {
                   7239:     my ($r)=@_;
1.414     droeschl 7240:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=addmetadata',
1.473     amueller 7241:         text=>"Add Metadata Field"});
1.334     banghart 7242:     $r->print(&Apache::loncommon::start_page('Add Metadata Field'));
                   7243:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Add Metadata Field'));
1.335     banghart 7244:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7245:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7246:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   7247:     &startSettingsScreen($r,'parmset',$crstype);
1.339     banghart 7248:     if (exists($env{'form.undelete'})) {
1.358     banghart 7249:         my @meta_fields = &Apache::loncommon::get_env_multiple('form.undeletefield');
1.339     banghart 7250:         foreach my $meta_field(@meta_fields) {
                   7251:             my $options = $env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.options'};
                   7252:             $options =~ s/deleted//;
                   7253:             $options =~ s/,,/,/;
                   7254:             my $put_result = &Apache::lonnet::put('environment',
                   7255:                                         {'metadata.'.$meta_field.'.options'=>$options},$dom,$crs);
1.446     bisitz   7256: 
1.586     raeburn  7257:             $r->print(&mt('Undeleted Metadata Field [_1] with result [_2]',
                   7258:                           '<strong>'.$env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.added'}.
                   7259:                           '</strong>',$put_result).
                   7260:                       '<br />');
1.339     banghart 7261:         }
1.359     banghart 7262:         $r->print(&continue());
1.339     banghart 7263:     } elsif (exists($env{'form.fieldname'})) {
1.335     banghart 7264:         my $meta_field = $env{'form.fieldname'};
                   7265:         my $display_field = $env{'form.fieldname'};
                   7266:         $meta_field =~ s/\W/_/g;
1.338     banghart 7267:         $meta_field =~ tr/A-Z/a-z/;
1.335     banghart 7268:         my $put_result = &Apache::lonnet::put('environment',
                   7269:                             {'metadata.'.$meta_field.'.values'=>"",
                   7270:                              'metadata.'.$meta_field.'.added'=>"$display_field",
                   7271:                              'metadata.'.$meta_field.'.options'=>""},$dom,$crs);
1.586     raeburn  7272:         $r->print(&mt('Added new Metadata Field [_1] with result [_2]',
                   7273:                       '<strong>'.$env{'form.fieldname'}.'</strong>',$put_result).
                   7274:                   '<br />');
1.359     banghart 7275:         $r->print(&continue());
1.335     banghart 7276:     } else {
1.357     raeburn  7277:         my $fields = &get_deleted_meta_fieldnames($env{'request.course.id'});
1.339     banghart 7278:         if ($fields) {
1.586     raeburn  7279:             $r->print(&mt('You may undelete previously deleted fields.').
                   7280:                       '<br />'.
                   7281:                       &mt('Check those you wish to undelete and click Undelete.').
                   7282:                       '<br />');
1.339     banghart 7283:             $r->print('<form method="post" action="">');
                   7284:             foreach my $key(keys(%$fields)) {
1.581     raeburn  7285:                 $r->print('<label><input type="checkbox" name="undeletefield" value="'.$key.'" />'.$$fields{$key}.'</label><br /');
1.339     banghart 7286:             }
1.586     raeburn  7287:             $r->print('<input type="submit" name="undelete" value="'.&mt('Undelete').'" />');
1.339     banghart 7288:             $r->print('</form>');
                   7289:         }
1.586     raeburn  7290:         $r->print('<hr />'.
                   7291:                   &mt('[_1]Or[_2] you may enter a new metadata field name.',
                   7292:                       '<strong>','</strong>').
1.581     raeburn  7293:                   '<form method="post" action="/adm/parmset?action=addmetadata">');
1.335     banghart 7294:         $r->print('<input type="text" name="fieldname" /><br />');
1.586     raeburn  7295:         $r->print('<input type="submit" value="'.&mt('Add Metadata Field').'" />');
1.581     raeburn  7296:         $r->print('</form>');
1.334     banghart 7297:     }
1.507     www      7298:     &endSettingsScreen($r);
1.334     banghart 7299: }
1.416     jms      7300: 
                   7301: 
                   7302: 
1.560     damieng  7303: # Display or save portfolio metadata.
1.563     damieng  7304: #
                   7305: # @param {Apache2::RequestRec} $r - the Apache request
1.259     banghart 7306: sub setrestrictmeta {
1.240     banghart 7307:     my ($r)=@_;
1.242     banghart 7308:     my $next_meta;
1.244     banghart 7309:     my $output;
1.245     banghart 7310:     my $item_num;
1.246     banghart 7311:     my $put_result;
1.414     droeschl 7312:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setrestrictmeta',
1.473     amueller 7313:         text=>"Restrict Metadata"});
1.280     albertel 7314:     $r->print(&Apache::loncommon::start_page('Restrict Metadata'));
1.298     albertel 7315:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Restrict Metadata'));
1.240     banghart 7316:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7317:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7318:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   7319:     &startSettingsScreen($r,'parmset',$crstype);
1.259     banghart 7320:     my $key_base = $env{'course.'.$env{'request.course.id'}.'.'};
1.252     banghart 7321:     my $save_field = '';
1.586     raeburn  7322:     my %lt = &Apache::lonlocal::texthash(
                   7323:                                            addm => 'Add Metadata Field',
                   7324:                                            ordm => 'Order Metadata Fields',
                   7325:                                            save => 'Save',
                   7326:                                         );
1.259     banghart 7327:     if ($env{'form.restrictmeta'}) {
1.254     banghart 7328:         foreach my $field (sort(keys(%env))) {
1.252     banghart 7329:             if ($field=~m/^form.(.+)_(.+)$/) {
1.254     banghart 7330:                 my $options;
1.252     banghart 7331:                 my $meta_field = $1;
                   7332:                 my $meta_key = $2;
1.253     banghart 7333:                 if ($save_field ne $meta_field) {
1.252     banghart 7334:                     $save_field = $meta_field;
1.473     amueller 7335:                     if ($env{'form.'.$meta_field.'_stuadd'}) {
                   7336:                         $options.='stuadd,';
                   7337:                     }
                   7338:                     if ($env{'form.'.$meta_field.'_choices'}) {
                   7339:                         $options.='choices,';
                   7340:                     }
                   7341:                     if ($env{'form.'.$meta_field.'_onlyone'} eq 'single') {
                   7342:                         $options.='onlyone,';
                   7343:                     }
                   7344:                     if ($env{'form.'.$meta_field.'_active'}) {
                   7345:                         $options.='active,';
                   7346:                     }
                   7347:                     if ($env{'form.'.$meta_field.'_deleted'}) {
                   7348:                         $options.='deleted,';
                   7349:                     }
1.259     banghart 7350:                     my $name = $save_field;
1.560     damieng  7351:                     $put_result = &Apache::lonnet::put('environment',
                   7352:                         {'metadata.'.$meta_field.'.options'=>$options,
                   7353:                         'metadata.'.$meta_field.'.values'=>$env{'form.'.$meta_field.'_values'},
                   7354:                         },$dom,$crs);
1.252     banghart 7355:                 }
                   7356:             }
                   7357:         }
                   7358:     }
1.296     albertel 7359:     &Apache::lonnet::coursedescription($env{'request.course.id'},
1.473     amueller 7360:                        {'freshen_cache' => 1});
1.335     banghart 7361:     # Get the default metadata fields
1.258     albertel 7362:     my %metadata_fields = &Apache::lonmeta::fieldnames('portfolio');
1.335     banghart 7363:     # Now get possible added metadata fields
1.357     raeburn  7364:     my $added_metadata_fields = &get_added_meta_fieldnames($env{'request.course.id'});
1.347     banghart 7365:     $output .= &Apache::loncommon::start_data_table();
1.258     albertel 7366:     foreach my $field (sort(keys(%metadata_fields))) {
1.265     banghart 7367:         if ($field ne 'courserestricted') {
1.586     raeburn  7368:             $output.= &output_row($r,$field,$metadata_fields{$field});
1.560     damieng  7369:         }
1.255     banghart 7370:     }
1.351     banghart 7371:     my $buttons = (<<ENDButtons);
1.586     raeburn  7372:         <input type="submit" name="restrictmeta" value="$lt{'save'}" />
1.351     banghart 7373:         </form><br />
                   7374:         <form method="post" action="/adm/parmset?action=addmetadata" name="form1">
1.586     raeburn  7375:         <input type="submit" name="restrictmeta" value="$lt{'addm'}" />
1.351     banghart 7376:         </form>
                   7377:         <br />
                   7378:         <form method="post" action="/adm/parmset?action=ordermetadata" name="form2">
1.586     raeburn  7379:         <input type="submit" name="restrictmeta" value="$lt{'ordm'}" />
1.351     banghart 7380: ENDButtons
1.337     banghart 7381:     my $added_flag = 1;
1.335     banghart 7382:     foreach my $field (sort(keys(%$added_metadata_fields))) {
1.586     raeburn  7383:         $output.= &output_row($r,$field,$$added_metadata_fields{$field},$added_flag);
1.335     banghart 7384:     }
1.347     banghart 7385:     $output .= &Apache::loncommon::end_data_table();
1.446     bisitz   7386:     $r->print(<<ENDenv);
1.259     banghart 7387:         <form method="post" action="/adm/parmset?action=setrestrictmeta" name="form">
1.244     banghart 7388:         $output
1.351     banghart 7389:         $buttons
1.340     banghart 7390:         </form>
1.244     banghart 7391: ENDenv
1.507     www      7392:     &endSettingsScreen($r);
1.280     albertel 7393:     $r->print(&Apache::loncommon::end_page());
1.240     banghart 7394:     return 'ok';
                   7395: }
1.416     jms      7396: 
                   7397: 
1.563     damieng  7398: # Returns metadata fields that have been manually added.
                   7399: #
                   7400: # @param {string} $cid - course id
                   7401: # @returns {hash reference} - hash field name -> field title (not localized)
1.335     banghart 7402: sub get_added_meta_fieldnames {
1.357     raeburn  7403:     my ($cid) = @_;
1.335     banghart 7404:     my %fields;
                   7405:     foreach my $key(%env) {
1.357     raeburn  7406:         if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) {
1.335     banghart 7407:             my $field_name = $1;
                   7408:             my ($display_field_name) = $env{$key};
                   7409:             $fields{$field_name} = $display_field_name;
                   7410:         }
                   7411:     }
                   7412:     return \%fields;
                   7413: }
1.416     jms      7414: 
                   7415: 
1.563     damieng  7416: # Returns metadata fields that have been manually added and deleted.
                   7417: #
                   7418: # @param {string} $cid - course id
                   7419: # @returns {hash reference} - hash field name -> field title (not localized)
1.339     banghart 7420: sub get_deleted_meta_fieldnames {
1.357     raeburn  7421:     my ($cid) = @_;
1.339     banghart 7422:     my %fields;
                   7423:     foreach my $key(%env) {
1.357     raeburn  7424:         if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) {
1.339     banghart 7425:             my $field_name = $1;
                   7426:             if ($env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.options'} =~ m/deleted/) {
                   7427:                 my ($display_field_name) = $env{$key};
                   7428:                 $fields{$field_name} = $display_field_name;
                   7429:             }
                   7430:         }
                   7431:     }
                   7432:     return \%fields;
                   7433: }
1.560     damieng  7434: 
                   7435: 
                   7436: ##################################################
                   7437: # PARAMETER SETTINGS DEFAULT ACTIONS
                   7438: ##################################################
                   7439: 
                   7440: # UI to change parameter setting default actions
1.563     damieng  7441: #
                   7442: # @param {Apache2::RequestRec} $r - the Apache request
1.220     www      7443: sub defaultsetter {
1.280     albertel 7444:     my ($r) = @_;
                   7445: 
1.414     droeschl 7446:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setdefaults',
1.473     amueller 7447:         text=>"Set Defaults"});
1.531     raeburn  7448:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7449:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   7450:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.446     bisitz   7451:     my $start_page =
1.531     raeburn  7452:         &Apache::loncommon::start_page('Parameter Setting Default Actions');
1.298     albertel 7453:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Defaults');
1.507     www      7454:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  7455:     &startSettingsScreen($r,'parmset',$crstype);
1.507     www      7456:     $r->print('<form method="post" action="/adm/parmset?action=setdefaults" name="defaultform">');
1.280     albertel 7457: 
1.221     www      7458:     my @ids=();
                   7459:     my %typep=();
                   7460:     my %keyp=();
                   7461:     my %allparms=();
                   7462:     my %allparts=();
                   7463:     my %allmaps=();
                   7464:     my %mapp=();
                   7465:     my %symbp=();
                   7466:     my %maptitles=();
                   7467:     my %uris=();
                   7468:     my %keyorder=&standardkeyorder();
                   7469:     my %defkeytype=();
                   7470: 
1.446     bisitz   7471:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 7472:                 \%mapp, \%symbp,\%maptitles,\%uris,
                   7473:                 \%keyorder,\%defkeytype);
1.224     www      7474:     if ($env{'form.storerules'}) {
1.560     damieng  7475:         my %newrules=();
                   7476:         my @delrules=();
                   7477:         my %triggers=();
                   7478:         foreach my $key (keys(%env)) {
1.225     albertel 7479:             if ($key=~/^form\.(\w+)\_action$/) {
1.560     damieng  7480:                 my $tempkey=$1;
                   7481:                 my $action=$env{$key};
1.226     www      7482:                 if ($action) {
1.560     damieng  7483:                     $newrules{$tempkey.'_action'}=$action;
                   7484:                     if ($action ne 'default') {
                   7485:                         my ($whichaction,$whichparm)=($action=~/^(.*\_)([^\_]+)$/);
                   7486:                         $triggers{$whichparm}.=$tempkey.':';
                   7487:                     }
                   7488:                     $newrules{$tempkey.'_type'}=$defkeytype{$tempkey};
                   7489:                     if (&isdateparm($defkeytype{$tempkey})) {
                   7490:                         $newrules{$tempkey.'_days'}=$env{'form.'.$tempkey.'_days'};
                   7491:                         $newrules{$tempkey.'_hours'}=$env{'form.'.$tempkey.'_hours'};
                   7492:                         $newrules{$tempkey.'_min'}=$env{'form.'.$tempkey.'_min'};
                   7493:                         $newrules{$tempkey.'_sec'}=$env{'form.'.$tempkey.'_sec'};
                   7494:                     } else {
                   7495:                         $newrules{$tempkey.'_value'}=$env{'form.'.$tempkey.'_value'};
                   7496:                         $newrules{$tempkey.'_triggervalue'}=$env{'form.'.$tempkey.'_triggervalue'};
                   7497:                     }
                   7498:                 } else {
                   7499:                     push(@delrules,$tempkey.'_action');
                   7500:                     push(@delrules,$tempkey.'_type');
                   7501:                     push(@delrules,$tempkey.'_hours');
                   7502:                     push(@delrules,$tempkey.'_min');
                   7503:                     push(@delrules,$tempkey.'_sec');
                   7504:                     push(@delrules,$tempkey.'_value');
                   7505:                 }
1.473     amueller 7506:             }
                   7507:         }
1.560     damieng  7508:         foreach my $key (keys(%allparms)) {
                   7509:             $newrules{$key.'_triggers'}=$triggers{$key};
1.473     amueller 7510:         }
1.560     damieng  7511:         &Apache::lonnet::put('parmdefactions',\%newrules,$cdom,$cnum);
                   7512:         &Apache::lonnet::del('parmdefactions',\@delrules,$cdom,$cnum);
                   7513:         &resetrulescache();
1.224     www      7514:     }
1.227     www      7515:     my %lt=&Apache::lonlocal::texthash('days' => 'Days',
1.473     amueller 7516:                        'hours' => 'Hours',
                   7517:                        'min' => 'Minutes',
                   7518:                        'sec' => 'Seconds',
                   7519:                        'yes' => 'Yes',
                   7520:                        'no' => 'No');
1.222     www      7521:     my @standardoptions=('','default');
                   7522:     my @standarddisplay=('',&mt('Default value when manually setting'));
                   7523:     my @dateoptions=('','default');
                   7524:     my @datedisplay=('',&mt('Default value when manually setting'));
                   7525:     foreach my $tempkey (&keysindisplayorder(\%allparms,\%keyorder)) {
1.560     damieng  7526:         unless ($tempkey) { next; }
                   7527:         push @standardoptions,'when_setting_'.$tempkey;
                   7528:         push @standarddisplay,&mt('Automatically set when setting ').$tempkey;
                   7529:         if (&isdateparm($defkeytype{$tempkey})) {
                   7530:             push @dateoptions,'later_than_'.$tempkey;
                   7531:             push @datedisplay,&mt('Automatically set later than ').$tempkey;
                   7532:             push @dateoptions,'earlier_than_'.$tempkey;
                   7533:             push @datedisplay,&mt('Automatically set earlier than ').$tempkey;
                   7534:         }
1.222     www      7535:     }
1.563     damieng  7536:     $r->print(&mt('Manual setting rules apply to all interfaces.').'<br />'.
                   7537:         &mt('Automatic setting rules apply to table mode interfaces only.'));
1.318     albertel 7538:     $r->print("\n".&Apache::loncommon::start_data_table().
1.473     amueller 7539:           &Apache::loncommon::start_data_table_header_row().
                   7540:           "<th>".&mt('Rule for parameter').'</th><th>'.
                   7541:           &mt('Action').'</th><th>'.&mt('Value').'</th>'.
                   7542:           &Apache::loncommon::end_data_table_header_row());
1.221     www      7543:     foreach my $tempkey (&keysindisplayorder(\%allparms,\%keyorder)) {
1.560     damieng  7544:         unless ($tempkey) { next; }
                   7545:         $r->print("\n".&Apache::loncommon::start_data_table_row().
                   7546:             "<td>".$allparms{$tempkey}."\n<br />(".$tempkey.')</td><td>');
                   7547:         my $action=&rulescache($tempkey.'_action');
                   7548:         $r->print('<select name="'.$tempkey.'_action">');
                   7549:         if (&isdateparm($defkeytype{$tempkey})) {
                   7550:             for (my $i=0;$i<=$#dateoptions;$i++) {
                   7551:             if ($dateoptions[$i]=~/\_$tempkey$/) { next; }
                   7552:             $r->print("\n<option value='$dateoptions[$i]'".
                   7553:                 ($dateoptions[$i] eq $action?' selected="selected"':'').
                   7554:                 ">$datedisplay[$i]</option>");
                   7555:             }
                   7556:         } else {
                   7557:             for (my $i=0;$i<=$#standardoptions;$i++) {
                   7558:             if ($standardoptions[$i]=~/\_$tempkey$/) { next; }
                   7559:             $r->print("\n<option value='$standardoptions[$i]'".
                   7560:                 ($standardoptions[$i] eq $action?' selected="selected"':'').
                   7561:                 ">$standarddisplay[$i]</option>");
                   7562:             }
1.473     amueller 7563:         }
1.560     damieng  7564:         $r->print('</select>');
                   7565:         unless (&isdateparm($defkeytype{$tempkey})) {
                   7566:             $r->print("\n<br />".&mt('Triggering value(s) of other parameter (optional, comma-separated):').
                   7567:                 '<input type="text" size="20" name="'.$tempkey.'_triggervalue" value="'.&rulescache($tempkey.'_triggervalue').'" />');
1.473     amueller 7568:         }
1.560     damieng  7569:         $r->print("\n</td><td>\n");
1.222     www      7570: 
1.221     www      7571:         if (&isdateparm($defkeytype{$tempkey})) {
1.560     damieng  7572:             my $days=&rulescache($tempkey.'_days');
                   7573:             my $hours=&rulescache($tempkey.'_hours');
                   7574:             my $min=&rulescache($tempkey.'_min');
                   7575:             my $sec=&rulescache($tempkey.'_sec');
                   7576:             $r->print(<<ENDINPUTDATE);
                   7577:     <input name="$tempkey\_days" type="text" size="4" value="$days" />$lt{'days'}<br />
                   7578:     <input name="$tempkey\_hours" type="text" size="4" value="$hours" />$lt{'hours'}<br />
                   7579:     <input name="$tempkey\_min" type="text" size="4" value="$min" />$lt{'min'}<br />
                   7580:     <input name="$tempkey\_sec" type="text" size="4" value="$sec" />$lt{'sec'}
1.564     raeburn  7581: ENDINPUTDATE
1.560     damieng  7582:         } elsif ($defkeytype{$tempkey} eq 'string_yesno') {
                   7583:                 my $yeschecked='';
                   7584:                 my $nochecked='';
                   7585:                 if (&rulescache($tempkey.'_value') eq 'yes') { $yeschecked=' checked="checked"'; }
                   7586:                 if (&rulescache($tempkey.'_value') eq 'no') { $nochecked=' checked="checked"'; }
                   7587: 
                   7588:             $r->print(<<ENDYESNO);
                   7589:     <label><input type="radio" name="$tempkey\_value" value="yes"$yeschecked /> $lt{'yes'}</label><br />
                   7590:     <label><input type="radio" name="$tempkey\_value" value="no"$nochecked /> $lt{'no'}</label>
1.564     raeburn  7591: ENDYESNO
1.221     www      7592:         } else {
1.560     damieng  7593:             $r->print('<input type="text" size="20" name="'.$tempkey.'_value" value="'.&rulescache($tempkey.'_value').'" />');
                   7594:         }
1.318     albertel 7595:         $r->print('</td>'.&Apache::loncommon::end_data_table_row());
1.221     www      7596:     }
1.318     albertel 7597:     $r->print(&Apache::loncommon::end_data_table().
1.473     amueller 7598:           "\n".'<input type="submit" name="storerules" value="'.
1.507     www      7599:           &mt('Save').'" /></form>'."\n");
                   7600:     &endSettingsScreen($r);
                   7601:     $r->print(&Apache::loncommon::end_page());
1.220     www      7602:     return;
                   7603: }
1.193     albertel 7604: 
1.560     damieng  7605: ##################################################
                   7606: # PARAMETER CHANGES LOG
                   7607: ##################################################
                   7608: 
1.563     damieng  7609: # Returns some info for a parameter log entry.
                   7610: # Returned entries:
                   7611: # $realm - HTML title for the parameter level and resource
                   7612: # $section - parameter section
                   7613: # $name - parameter name
                   7614: # $part - parameter part
                   7615: # $what - $part.'.'.$name
                   7616: # $middle - resource symb ?
                   7617: # $uname - user name (same as given)
                   7618: # $udom - user domain (same as given)
                   7619: # $issection - section or group name
                   7620: # $realmdescription - title for the parameter level and resource (without using HTML)
                   7621: #
                   7622: # @param {string} $key - parameter log key
                   7623: # @param {string} $uname - user name
                   7624: # @param {string} $udom - user domain
                   7625: # @param {boolean} $typeflag - .type log entry
                   7626: # @returns {Array}
1.290     www      7627: sub components {
1.581     raeburn  7628:     my ($key,$uname,$udom,$typeflag)=@_;
1.330     albertel 7629: 
                   7630:     if ($typeflag) {
1.560     damieng  7631:         $key=~s/\.type$//;
1.290     www      7632:     }
1.330     albertel 7633: 
                   7634:     my ($middle,$part,$name)=
1.572     damieng  7635:         ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.291     www      7636:     my $issection;
1.330     albertel 7637: 
1.290     www      7638:     my $section=&mt('All Students');
                   7639:     if ($middle=~/^\[(.*)\]/) {
1.560     damieng  7640:         $issection=$1;
                   7641:         $section=&mt('Group/Section').': '.$issection;
                   7642:         $middle=~s/^\[(.*)\]//;
1.290     www      7643:     }
                   7644:     $middle=~s/\.+$//;
                   7645:     $middle=~s/^\.+//;
1.291     www      7646:     if ($uname) {
1.560     damieng  7647:         $section=&mt('User').": ".&Apache::loncommon::plainname($uname,$udom);
                   7648:         $issection='';
1.291     www      7649:     }
1.316     albertel 7650:     my $realm='<span class="LC_parm_scope_all">'.&mt('All Resources').'</span>';
1.446     bisitz   7651:     my $realmdescription=&mt('all resources');
1.556     raeburn  7652:     if ($middle=~/^(.+)\_\_\_\((all|rec)\)$/) {
                   7653:         my $mapurl = $1;
                   7654:         my $maplevel = $2;
                   7655:         my $leveltitle = &mt('Folder/Map');
                   7656:         if ($maplevel eq 'rec') {
                   7657:             $leveltitle = &mt('Recursive');
                   7658:         }
1.560     damieng  7659:         $realm='<span class="LC_parm_scope_folder">'.$leveltitle.
                   7660:             ': '.&Apache::lonnet::gettitle($mapurl).' <span class="LC_parm_folder"><br />('.
                   7661:             $mapurl.')</span></span>';
                   7662:         $realmdescription=&mt('folder').' '.&Apache::lonnet::gettitle($mapurl);
                   7663:     } elsif ($middle) {
                   7664:         my ($map,$id,$url)=&Apache::lonnet::decode_symb($middle);
                   7665:         $realm='<span class="LC_parm_scope_resource">'.&mt('Resource').
                   7666:             ': '.&Apache::lonnet::gettitle($middle).' <br /><span class="LC_parm_symb">('.$url.
                   7667:             ' in '.$map.' id: '.$id.')</span></span>';
                   7668:         $realmdescription=&mt('resource').' '.&Apache::lonnet::gettitle($middle);
1.290     www      7669:     }
1.291     www      7670:     my $what=$part.'.'.$name;
1.330     albertel 7671:     return ($realm,$section,$name,$part,
1.473     amueller 7672:         $what,$middle,$uname,$udom,$issection,$realmdescription);
1.290     www      7673: }
1.293     www      7674: 
1.563     damieng  7675: my %standard_parms; # hash parameter name -> parameter title (not localized)
                   7676: my %standard_parms_types; # hash parameter name -> parameter type
1.416     jms      7677: 
1.563     damieng  7678: # Reads parameter info from packages.tab into %standard_parms.
1.328     albertel 7679: sub load_parameter_names {
1.583     raeburn  7680:     open(my $config,"<","$Apache::lonnet::perlvar{'lonTabDir'}/packages.tab");
1.328     albertel 7681:     while (my $configline=<$config>) {
1.560     damieng  7682:         if ($configline !~ /\S/ || $configline=~/^\#/) { next; }
                   7683:         chomp($configline);
                   7684:         my ($short,$plain)=split(/:/,$configline);
                   7685:         my (undef,$name,$type)=split(/\&/,$short,3);
                   7686:         if ($type eq 'display') {
                   7687:             $standard_parms{$name} = $plain;
1.469     raeburn  7688:         } elsif ($type eq 'type') {
1.560     damieng  7689:                 $standard_parms_types{$name} = $plain;
1.469     raeburn  7690:         }
1.328     albertel 7691:     }
                   7692:     close($config);
                   7693:     $standard_parms{'int_pos'}      = 'Positive Integer';
                   7694:     $standard_parms{'int_zero_pos'} = 'Positive Integer or Zero';
1.575     raeburn  7695:     $standard_parms{'scoreformat'}  = 'Format for display of score';
1.328     albertel 7696: }
                   7697: 
1.563     damieng  7698: # Returns a parameter title for standard parameters, the name for others.
                   7699: #
                   7700: # @param {string} $name - parameter name
                   7701: # @returns {string}
1.292     www      7702: sub standard_parameter_names {
                   7703:     my ($name)=@_;
1.328     albertel 7704:     if (!%standard_parms) {
1.560     damieng  7705:         &load_parameter_names();
1.328     albertel 7706:     }
1.292     www      7707:     if ($standard_parms{$name}) {
1.560     damieng  7708:         return $standard_parms{$name};
1.446     bisitz   7709:     } else {
1.560     damieng  7710:         return $name;
1.292     www      7711:     }
                   7712: }
1.290     www      7713: 
1.563     damieng  7714: # Returns a parameter type for standard parameters, undef for others.
                   7715: #
                   7716: # @param {string} $name - parameter name
                   7717: # @returns {string}
1.469     raeburn  7718: sub standard_parameter_types {
                   7719:     my ($name)=@_;
                   7720:     if (!%standard_parms_types) {
                   7721:         &load_parameter_names();
                   7722:     }
                   7723:     if ($standard_parms_types{$name}) {
                   7724:         return $standard_parms_types{$name};
                   7725:     }
                   7726:     return;
                   7727: }
1.309     www      7728: 
1.563     damieng  7729: # Returns a parameter level title (not localized) from the parameter level name.
                   7730: #
                   7731: # @param {string} $name - parameter level name (recognized: resourcelevel|maplevel|maplevelrecurse|courselevel)
                   7732: # @returns {string}
1.557     raeburn  7733: sub standard_parameter_levels {
                   7734:     my ($name)=@_;
                   7735:     my %levels = (
                   7736:                     'resourcelevel'   => 'a single resource',
                   7737:                     'maplevel'        => 'the enclosing map/folder', 
                   7738:                     'maplevelrecurse' => 'the enclosing map/folder (recursive into sub-folders)',
                   7739:                     'courselevel'     => 'the general (course) level',
                   7740:                  );
                   7741:     if ($levels{$name}) {
                   7742:         return $levels{$name};
                   7743:     }
                   7744:     return;
                   7745: }
                   7746: 
1.560     damieng  7747: # Display log for parameter changes, blog postings, user notification changes.
1.563     damieng  7748: #
                   7749: # @param {Apache2::RequestRec} $r - the Apache request
1.285     albertel 7750: sub parm_change_log {
1.568     raeburn  7751:     my ($r,$parm_permission)=@_;
1.531     raeburn  7752:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7753:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.569     raeburn  7754:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.414     droeschl 7755:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=settable',
1.473     amueller 7756:     text=>"Parameter Change Log"});
1.522     raeburn  7757:     my $js = '<script type="text/javascript">'."\n".
                   7758:              '// <![CDATA['."\n".
                   7759:              &Apache::loncommon::display_filter_js('parmslog')."\n".
                   7760:              '// ]]>'."\n".
                   7761:              '</script>'."\n";
                   7762:     $r->print(&Apache::loncommon::start_page('Parameter Change Log',$js));
1.327     albertel 7763:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Parameter Change Log'));
1.531     raeburn  7764:     &startSettingsScreen($r,'parmset',$crstype);
                   7765:     my %parmlog=&Apache::lonnet::dump('nohist_parameterlog',$cdom,$cnum);
1.311     albertel 7766: 
1.301     www      7767:     if ((keys(%parmlog))[0]=~/^error\:/) { undef(%parmlog); }
1.311     albertel 7768: 
1.522     raeburn  7769:     $r->print('<div class="LC_left_float">'.
                   7770:               '<fieldset><legend>'.&mt('Display of Changes').'</legend>'.
                   7771:               '<form action="/adm/parmset?action=parameterchangelog"
1.327     albertel 7772:                      method="post" name="parameterlog">');
1.446     bisitz   7773: 
1.311     albertel 7774:     my %saveable_parameters = ('show' => 'scalar',);
                   7775:     &Apache::loncommon::store_course_settings('parameter_log',
                   7776:                                               \%saveable_parameters);
                   7777:     &Apache::loncommon::restore_course_settings('parameter_log',
                   7778:                                                 \%saveable_parameters);
1.522     raeburn  7779:     $r->print(&Apache::loncommon::display_filter('parmslog').'&nbsp;'."\n".
                   7780:               '<input type="submit" value="'.&mt('Display').'" />'.
                   7781:               '</form></fieldset></div><br clear="all" />');
1.301     www      7782: 
1.568     raeburn  7783:     my $readonly = 1;
                   7784:     if ($parm_permission->{'edit'}) {
                   7785:         undef($readonly);
                   7786:     }
1.531     raeburn  7787:     my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
1.301     www      7788:     $r->print(&Apache::loncommon::start_data_table().&Apache::loncommon::start_data_table_header_row().
1.473     amueller 7789:           '<th>'.&mt('Time').'</th><th>'.&mt('User').'</th><th>'.&mt('Extent').'</th><th>'.&mt('Users').'</th><th>'.
1.568     raeburn  7790:           &mt('Parameter').'</th><th>'.&mt('Part').'</th><th>'.&mt('New Value').'</th>');
                   7791:     unless ($readonly) {
                   7792:         $r->print('<th>'.&mt('Announce').'</th>');
                   7793:     }
                   7794:     $r->print(&Apache::loncommon::end_data_table_header_row());
1.309     www      7795:     my $shown=0;
1.349     www      7796:     my $folder='';
                   7797:     if ($env{'form.displayfilter'} eq 'currentfolder') {
1.560     damieng  7798:         my $last='';
                   7799:         if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
                   7800:                 &GDBM_READER(),0640)) {
                   7801:             $last=$hash{'last_known'};
                   7802:             untie(%hash);
                   7803:         }
                   7804:         if ($last) { ($folder) = &Apache::lonnet::decode_symb($last); }
                   7805:     }
1.595     raeburn  7806:     my $numgroups = 0;
                   7807:     my @groups;
                   7808:     if ($env{'request.course.groups'} ne '') {
                   7809:         @groups = split(/:/,$env{'request.course.groups'});
                   7810:         $numgroups = scalar(@groups);
                   7811:     }
1.560     damieng  7812:     foreach my $id (sort {
                   7813:                 if ($parmlog{$b}{'exe_time'} ne $parmlog{$a}{'exe_time'}) {
                   7814:                     return $parmlog{$b}{'exe_time'} <=>$parmlog{$a}{'exe_time'}
                   7815:                 }
                   7816:                 my $aid = (split('00000',$a))[-1];
                   7817:                 my $bid = (split('00000',$b))[-1];
                   7818:                 return $bid<=>$aid;
1.473     amueller 7819:             } (keys(%parmlog))) {
1.294     www      7820:         my @changes=keys(%{$parmlog{$id}{'logentry'}});
1.560     damieng  7821:         my $count = 0;
                   7822:         my $time =
                   7823:             &Apache::lonlocal::locallocaltime($parmlog{$id}{'exe_time'});
                   7824:         my $plainname =
                   7825:             &Apache::loncommon::plainname($parmlog{$id}{'exe_uname'},
                   7826:                         $parmlog{$id}{'exe_udom'});
                   7827:         my $about_me_link =
                   7828:             &Apache::loncommon::aboutmewrapper($plainname,
                   7829:                             $parmlog{$id}{'exe_uname'},
                   7830:                             $parmlog{$id}{'exe_udom'});
                   7831:         my $send_msg_link='';
1.568     raeburn  7832:         if ((!$readonly) && 
                   7833:             (($parmlog{$id}{'exe_uname'} ne $env{'user.name'})
1.560     damieng  7834:             || ($parmlog{$id}{'exe_udom'} ne $env{'user.domain'}))) {
                   7835:             $send_msg_link ='<br />'.
                   7836:             &Apache::loncommon::messagewrapper(&mt('Send message'),
                   7837:                             $parmlog{$id}{'exe_uname'},
                   7838:                             $parmlog{$id}{'exe_udom'});
                   7839:         }
                   7840:         my $row_start=&Apache::loncommon::start_data_table_row();
                   7841:         my $makenewrow=0;
                   7842:         my %istype=();
                   7843:         my $output;
                   7844:         foreach my $changed (reverse(sort(@changes))) {
                   7845:                 my $value=$parmlog{$id}{'logentry'}{$changed};
                   7846:             my $typeflag = ($changed =~/\.type$/ &&
                   7847:                     !exists($parmlog{$id}{'logentry'}{$changed.'.type'}));
1.330     albertel 7848:             my ($realm,$section,$parmname,$part,$what,$middle,$uname,$udom,$issection,$realmdescription)=
1.581     raeburn  7849:                 &components($changed,$parmlog{$id}{'uname'},$parmlog{$id}{'udom'},$typeflag);
1.560     damieng  7850:             if ($env{'request.course.sec'} ne '') {
1.595     raeburn  7851:                 next if (($issection ne '') && (!(($issection eq $env{'request.course.sec'}) ||
                   7852:                                                   ($numgroups && (grep(/^\Q$issection\E$/,@groups))))));
1.560     damieng  7853:                 if ($uname ne '') {
                   7854:                     my $stusection = &Apache::lonnet::getsection($uname,$udom,$env{'request.course.id'});
                   7855:                     next if (($stusection ne '-1') && ($stusection ne $env{'request.course.sec'})); 
                   7856:                 }
                   7857:             }
                   7858:             if ($env{'form.displayfilter'} eq 'currentfolder') {
                   7859:                 if ($folder) {
                   7860:                     if ($middle!~/^\Q$folder\E/) { next; }
                   7861:                 }
                   7862:             }
                   7863:             if ($typeflag) {
                   7864:                 $istype{$parmname}=$value;
                   7865:                 if (!$env{'form.includetypes'}) { next; }
                   7866:             }
                   7867:             $count++;
                   7868:             if ($makenewrow) {
                   7869:                 $output .= $row_start;
                   7870:             } else {
                   7871:                 $makenewrow=1;
                   7872:             }
1.470     raeburn  7873:             my $parmitem = &standard_parameter_names($parmname);
1.560     damieng  7874:             $output .='<td>'.$realm.'</td><td>'.$section.'</td><td>'.
                   7875:                 &mt($parmitem).'</td><td>'.
                   7876:                 ($part?&mt('Part: [_1]',$part):&mt('All Parts')).'</td><td>';
                   7877:             my $stillactive=0;
                   7878:             if ($parmlog{$id}{'delflag'}) {
                   7879:                 $output .= &mt('Deleted');
                   7880:             } else {
                   7881:                 if ($typeflag) {
1.470     raeburn  7882:                     my $parmitem = &standard_parameter_names($value); 
                   7883:                     $parmitem = &mt($parmitem);
1.560     damieng  7884:                     $output .= &mt('Type: [_1]',$parmitem);
                   7885:                 } else {
1.584     raeburn  7886:                     my $toolsymb;
                   7887:                     if ($middle =~ /ext\.tool$/) {
                   7888:                         $toolsymb = $middle;
                   7889:                     }
1.560     damieng  7890:                     my ($level,@all)=&parmval_by_symb($what,$middle,
1.584     raeburn  7891:                         &Apache::lonnet::metadata($middle,$what,$toolsymb),
1.560     damieng  7892:                         $uname,$udom,$issection,$issection,$courseopt);
1.469     raeburn  7893:                     my $showvalue = $value;
                   7894:                     if ($istype{$parmname} eq '') {
                   7895:                         my $type = &standard_parameter_types($parmname);
                   7896:                         if ($type ne '') {
                   7897:                             if (&isdateparm($type)) {
                   7898:                                 $showvalue =
                   7899:                                     &Apache::lonlocal::locallocaltime($value);
                   7900:                             }
                   7901:                         }
                   7902:                     } else {
1.560     damieng  7903:                         if (&isdateparm($istype{$parmname})) {
                   7904:                             $showvalue = &Apache::lonlocal::locallocaltime($value);
1.622     raeburn  7905:                         } elsif (($istype{$parmname} eq 'string_grace') ||
                   7906:                                  ($istype{$parmname} eq 'string_ip')) {
                   7907:                             $showvalue =~ s/,/, /g;
1.560     damieng  7908:                         }
1.469     raeburn  7909:                     }
                   7910:                     $output .= $showvalue;
1.560     damieng  7911:                     if ($value ne $all[$level]) {
                   7912:                         $output .= '<br /><span class="LC_warning">'.&mt('Not active anymore').'</span>';
                   7913:                     } else {
                   7914:                         $stillactive=1;
                   7915:                     }
                   7916:                 }
1.473     amueller 7917:             }
1.568     raeburn  7918:             $output .= '</td>';
                   7919: 
                   7920:             unless ($readonly) { 
                   7921:                 $output .= '<td>';
                   7922:                 if ($stillactive) {
                   7923:                     my $parmitem = &standard_parameter_names($parmname);
                   7924:                     $parmitem = &mt($parmitem);
                   7925:                     my $title=&mt('Changed [_1]',$parmitem);
                   7926:                     my $description=&mt('Changed [_1] for [_2] to [_3]',
                   7927:                         $parmitem,$realmdescription,
                   7928:                         (&isdateparm($istype{$parmname})?&Apache::lonlocal::locallocaltime($value):$value));
                   7929:                     if (($uname) && ($udom)) {
                   7930:                         $output .=
                   7931:                         &Apache::loncommon::messagewrapper('Notify User',
                   7932:                                                            $uname,$udom,$title,
                   7933:                                                            $description);
                   7934:                     } else {
                   7935:                         $output .=
                   7936:                             &Apache::lonrss::course_blog_link($id,$title,
                   7937:                                                               $description);
                   7938:                     }
1.560     damieng  7939:                 }
1.568     raeburn  7940:                 $output .= '</td>';
1.560     damieng  7941:             }
1.568     raeburn  7942:             $output .= &Apache::loncommon::end_data_table_row();
1.473     amueller 7943:         }
1.560     damieng  7944:         if ($env{'form.displayfilter'} eq 'containing') {
                   7945:             my $wholeentry=$about_me_link.':'.
                   7946:             $parmlog{$id}{'exe_uname'}.':'.$parmlog{$id}{'exe_udom'}.':'.
                   7947:             $output;
                   7948:             if ($wholeentry!~/\Q$env{'form.containingphrase'}\E/i) { next; }
1.473     amueller 7949:         }
1.349     www      7950:         if ($count) {
1.560     damieng  7951:             $r->print($row_start.'<td rowspan="'.$count.'">'.$time.'</td>
                   7952:                         <td rowspan="'.$count.'">'.$about_me_link.
                   7953:             '<br /><tt>'.$parmlog{$id}{'exe_uname'}.
                   7954:                         ':'.$parmlog{$id}{'exe_udom'}.'</tt>'.
                   7955:             $send_msg_link.'</td>'.$output);
                   7956:             $shown++;
                   7957:         }
                   7958:         if (!($env{'form.show'} eq &mt('all')
                   7959:             || $shown<=$env{'form.show'})) { last; }
1.286     www      7960:     }
1.301     www      7961:     $r->print(&Apache::loncommon::end_data_table());
1.507     www      7962:     &endSettingsScreen($r);
1.284     www      7963:     $r->print(&Apache::loncommon::end_page());
                   7964: }
                   7965: 
1.560     damieng  7966: ##################################################
                   7967: # MISC !
                   7968: ##################################################
                   7969: 
1.563     damieng  7970: # Stores slot information.
1.560     damieng  7971: # Used by table UI
1.563     damieng  7972: # FIXME: I don't understand how this can work when the symb is not defined (if only a map was selected)
                   7973: #
                   7974: # @param {string} $slot_name - slot name
                   7975: # @param {string} $cdom - course domain
                   7976: # @param {string} $cnum - course number
                   7977: # @param {string} $symb - resource symb
                   7978: # @param {string} $uname - user name
                   7979: # @param {string} $udom - user domain
                   7980: # @returns {string} - 'ok' or error name
1.437     raeburn  7981: sub update_slots {
                   7982:     my ($slot_name,$cdom,$cnum,$symb,$uname,$udom) = @_;
                   7983:     my %slot=&Apache::lonnet::get_slot($slot_name);
                   7984:     if (!keys(%slot)) {
                   7985:         return 'error: slot does not exist';
                   7986:     }
                   7987:     my $max=$slot{'maxspace'};
                   7988:     if (!defined($max)) { $max=99999; }
                   7989: 
                   7990:     my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum,
                   7991:                                        "^$slot_name\0");
                   7992:     my ($tmp)=%consumed;
                   7993:     if ($tmp=~/^error: 2 / ) {
                   7994:         return 'error: unable to determine current slot status';
                   7995:     }
                   7996:     my $last=0;
                   7997:     foreach my $key (keys(%consumed)) {
                   7998:         my $num=(split('\0',$key))[1];
                   7999:         if ($num > $last) { $last=$num; }
                   8000:         if ($consumed{$key}->{'name'} eq $uname.':'.$udom) {
                   8001:             return 'ok';
                   8002:         }
                   8003:     }
                   8004: 
                   8005:     if (scalar(keys(%consumed)) >= $max) {
                   8006:         return 'error: no space left in slot';
                   8007:     }
                   8008:     my $wanted=$last+1;
                   8009: 
                   8010:     my %reservation=('name'      => $uname.':'.$udom,
                   8011:                      'timestamp' => time,
                   8012:                      'symb'      => $symb);
                   8013: 
                   8014:     my $success=&Apache::lonnet::newput('slot_reservations',
                   8015:                                         {"$slot_name\0$wanted" =>
                   8016:                                              \%reservation},
                   8017:                                         $cdom, $cnum);
1.438     raeburn  8018:     if ($success eq 'ok') {
                   8019:         my %storehash = (
                   8020:                           symb    => $symb,
                   8021:                           slot    => $slot_name,
                   8022:                           action  => 'reserve',
                   8023:                           context => 'parameter',
                   8024:                         );
1.526     raeburn  8025:         &Apache::lonnet::write_log('course','slotreservationslog',\%storehash,
1.524     raeburn  8026:                                    '',$uname,$udom,$cnum,$cdom);
1.438     raeburn  8027: 
1.526     raeburn  8028:         &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash,
1.524     raeburn  8029:                                    '',$uname,$udom,$uname,$udom);
1.438     raeburn  8030:     }
1.437     raeburn  8031:     return $success;
                   8032: }
                   8033: 
1.563     damieng  8034: # Deletes a slot reservation.
1.560     damieng  8035: # Used by table UI
1.563     damieng  8036: # FIXME: I don't understand how this can work when the symb is not defined (if only a map was selected)
                   8037: #
                   8038: # @param {string} $slot_name - slot name
                   8039: # @param {string} $cdom - course domain
                   8040: # @param {string} $cnum - course number
                   8041: # @param {string} $uname - user name
                   8042: # @param {string} $udom - user domain
                   8043: # @param {string} $symb - resource symb
                   8044: # @returns {string} - 'ok' or error name
1.437     raeburn  8045: sub delete_slots {
                   8046:     my ($slot_name,$cdom,$cnum,$uname,$udom,$symb) = @_;
                   8047:     my $delresult;
                   8048:     my %consumed = &Apache::lonnet::dump('slot_reservations',$cdom,
                   8049:                                          $cnum, "^$slot_name\0");
                   8050:     if (&Apache::lonnet::error(%consumed)) {
                   8051:         return 'error: unable to determine current slot status';
                   8052:     }
                   8053:     my ($tmp)=%consumed;
                   8054:     if ($tmp=~/^error: 2 /) {
                   8055:         return 'error: unable to determine current slot status';
                   8056:     }
                   8057:     foreach my $key (keys(%consumed)) {
                   8058:         if ($consumed{$key}->{'name'} eq $uname.':'.$udom) {
                   8059:             my $num=(split('\0',$key))[1];
                   8060:             my $entry = $slot_name.'\0'.$num;
                   8061:             $delresult = &Apache::lonnet::del('slot_reservations',[$entry],
                   8062:                                               $cdom,$cnum);
                   8063:             if ($delresult eq 'ok') {
                   8064:                 my %storehash = (
                   8065:                                   symb    => $symb,
                   8066:                                   slot    => $slot_name,
                   8067:                                   action  => 'release',
                   8068:                                   context => 'parameter',
                   8069:                                 );
1.526     raeburn  8070:                 &Apache::lonnet::write_log('course','slotreservationslog',\%storehash,
1.524     raeburn  8071:                                            1,$uname,$udom,$cnum,$cdom);
1.526     raeburn  8072:                 &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash,
1.524     raeburn  8073:                                            1,$uname,$udom,$uname,$udom);
1.437     raeburn  8074:             }
                   8075:         }
                   8076:     }
                   8077:     return $delresult;
                   8078: }
                   8079: 
1.563     damieng  8080: # Returns true if there is a current course.
1.560     damieng  8081: # Used by handler
1.563     damieng  8082: #
                   8083: # @returns {boolean}
1.355     albertel 8084: sub check_for_course_info {
                   8085:     my $navmap = Apache::lonnavmaps::navmap->new();
                   8086:     return 1 if ($navmap);
                   8087:     return 0;
                   8088: }
                   8089: 
1.563     damieng  8090: # Returns the current course host and host LON-CAPA version.
                   8091: #
                   8092: # @returns {Array} - (course hostname, major version number, minor version number)
1.514     raeburn  8093: sub parameter_release_vars { 
1.504     raeburn  8094:    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   8095:    my $chome = $env{'course.'.$env{'request.course.id'}.'.home'};
                   8096:    my $chostname = &Apache::lonnet::hostname($chome);
                   8097:    my ($cmajor,$cminor) = 
                   8098:        split(/\./,&Apache::lonnet::get_server_loncaparev($cdom,$chome));
                   8099:    return ($chostname,$cmajor,$cminor);
                   8100: }
                   8101: 
1.563     damieng  8102: # Checks if the course host version can handle a parameter required version,
                   8103: # and if it does, stores the release needed for the course.
                   8104: #
                   8105: # @param {string} $name - parameter name
                   8106: # @param {string} $value - parameter value
                   8107: # @param {string} $valmatch - name of the test used for checking the value
                   8108: # @param {string} $namematch - name of the test used for checking the name
                   8109: # @param {string} $needsrelease - version needed by the parameter, major.minor
                   8110: # @param {integer} $cmajor - course major version number
                   8111: # @param {integer} $cminor - course minor version number
                   8112: # @returns {boolean} - true if a newer version is needed
1.514     raeburn  8113: sub parameter_releasecheck {
1.557     raeburn  8114:     my ($name,$value,$valmatch,$namematch,$needsrelease,$cmajor,$cminor) = @_;
1.504     raeburn  8115:     my $needsnewer;
                   8116:     my ($needsmajor,$needsminor) = split(/\./,$needsrelease);
                   8117:     if (($cmajor < $needsmajor) || 
                   8118:         ($cmajor == $needsmajor && $cminor < $needsminor)) {
                   8119:         $needsnewer = 1;
1.557     raeburn  8120:     } elsif ($name) {
                   8121:         if ($valmatch) {
                   8122:             &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.'::'.$valmatch.':'});
                   8123:         } elsif ($value) { 
                   8124:             &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.':'.$value.'::'});
                   8125:         }
                   8126:     } elsif ($namematch) {
                   8127:         &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter::::'.$namematch});
1.504     raeburn  8128:     }
                   8129:     return $needsnewer;
                   8130: }
                   8131: 
1.568     raeburn  8132: sub get_permission {
                   8133:     my %permission;
                   8134:     my $allowed = 0;
                   8135:     return (\%permission,$allowed) unless ($env{'request.course.id'});
                   8136:     if ((&Apache::lonnet::allowed('opa',$env{'request.course.id'})) ||
                   8137:         (&Apache::lonnet::allowed('opa',$env{'request.course.id'}.'/'.
                   8138:                   $env{'request.course.sec'}))) {
                   8139:         %permission= (
                   8140:                        'edit'               => 1,
                   8141:                        'set'                => 1,
                   8142:                        'setoverview'        => 1,
                   8143:                        'addmetadata'        => 1,
                   8144:                        'ordermetadata'      => 1,
                   8145:                        'setrestrictmeta'    => 1,
                   8146:                        'newoverview'        => 1,
                   8147:                        'setdefaults'        => 1,
                   8148:                        'settable'           => 1,
                   8149:                        'parameterchangelog' => 1,
                   8150:                        'cleanparameters'    => 1,
                   8151:                        'dateshift1'         => 1,
                   8152:                        'dateshift2'         => 1,
                   8153:                        'helper'             => 1,
                   8154:          );
                   8155:     } elsif ((&Apache::lonnet::allowed('vpa',$env{'request.course.id'})) ||
                   8156:              (&Apache::lonnet::allowed('vpa',$env{'request.course.id'}.'/'.
                   8157:                   $env{'request.course.sec'}))) {
                   8158:         %permission = (
                   8159:                        'set'                => 1,
                   8160:                        'settable'           => 1,
                   8161:                        'newoverview'        => 1,
                   8162:                        'setoverview'        => 1,
                   8163:                        'parameterchangelog' => 1,
                   8164:                       );
                   8165:     }
                   8166:     foreach my $perm (values(%permission)) {
                   8167:         if ($perm) { $allowed=1; last; }
                   8168:     }
                   8169:     return (\%permission,$allowed);
                   8170: }
                   8171: 
1.560     damieng  8172: ##################################################
                   8173: # HANDLER
                   8174: ##################################################
                   8175: 
                   8176: # Main handler for lonparmset.
                   8177: # Sub called based on request parameters action and command:
                   8178: # no command or action: print_main_menu
                   8179: # command 'set': assessparms (direct access to table mode for a resource)
                   8180: #                (this can also be accessed simply with the symb parameter)
                   8181: # action 'setoverview': overview (display all existing parameter settings)
                   8182: # action 'addmetadata': addmetafield (called to add a portfolio metadata field)
                   8183: # action 'ordermetadata': order_meta_fields (called to order portfolio metadata fields)
                   8184: # action 'setrestrictmeta': setrestrictmeta (display or save portfolio metadata)
                   8185: # action 'newoverview': newoverview (overview mode)
                   8186: # action 'setdefaults': defaultsetter (UI to change parameter setting default actions)
                   8187: # action 'settable': assessparms (table mode)
                   8188: # action 'parameterchangelog': parm_change_log (display log for parameter changes,
                   8189: #                              blog postings, user notification changes)
                   8190: # action 'cleanparameters': clean_parameters (unused)
                   8191: # action 'dateshift1': date_shift_one (overview mode, shift all dates)
                   8192: # action 'dateshift2': date_shift_two (overview mode, shift all dates)
1.30      www      8193: sub handler {
1.43      albertel 8194:     my $r=shift;
1.30      www      8195: 
1.376     albertel 8196:     &reset_caches();
                   8197: 
1.414     droeschl 8198:     &Apache::loncommon::content_type($r,'text/html');
                   8199:     $r->send_http_header;
                   8200:     return OK if $r->header_only;
                   8201: 
1.193     albertel 8202:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.473     amueller 8203:                         ['action','state',
1.205     www      8204:                                              'pres_marker',
                   8205:                                              'pres_value',
1.206     www      8206:                                              'pres_type',
1.506     www      8207:                                              'filter','part',
1.390     www      8208:                                              'udom','uname','symb','serial','timebase']);
1.131     www      8209: 
1.83      bowersj2 8210: 
1.193     albertel 8211:     &Apache::lonhtmlcommon::clear_breadcrumbs();
1.194     albertel 8212:     &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/parmset",
1.507     www      8213:                         text=>"Content and Problem Settings",
1.473     amueller 8214:                         faq=>10,
                   8215:                         bug=>'Instructor Interface',
1.442     droeschl 8216:                                             help =>
                   8217:                                             'Parameter_Manager,Course_Environment,Parameter_Helper,Parameter_Overview,Table_Mode'});
1.203     www      8218: 
1.30      www      8219: # ----------------------------------------------------- Needs to be in a course
1.568     raeburn  8220:     my ($parm_permission,$allowed) = &get_permission();
1.355     albertel 8221:     my $exists = &check_for_course_info();
                   8222: 
1.568     raeburn  8223:     if ($env{'request.course.id'} && $allowed && $exists) {
1.193     albertel 8224:         #
                   8225:         # Main switch on form.action and form.state, as appropriate
                   8226:         #
                   8227:         # Check first if coming from someone else headed directly for
                   8228:         #  the table mode
1.568     raeburn  8229:         if (($parm_permission->{'set'}) && 
                   8230:             ((($env{'form.command'} eq 'set') && ($env{'form.url'})
                   8231:                 && (!$env{'form.dis'})) || ($env{'form.symb'}))) {
                   8232:             &assessparms($r,$parm_permission);
1.193     albertel 8233:         } elsif (! exists($env{'form.action'})) {
                   8234:             &print_main_menu($r,$parm_permission);
1.568     raeburn  8235:         } elsif (!$parm_permission->{$env{'form.action'}}) {
                   8236:             &print_main_menu($r,$parm_permission);
1.414     droeschl 8237:         } elsif ($env{'form.action'} eq 'setoverview') {
1.568     raeburn  8238:             &overview($r,$parm_permission);
1.560     damieng  8239:         } elsif ($env{'form.action'} eq 'addmetadata') {
                   8240:             &addmetafield($r);
                   8241:         } elsif ($env{'form.action'} eq 'ordermetadata') {
                   8242:             &order_meta_fields($r);
1.414     droeschl 8243:         } elsif ($env{'form.action'} eq 'setrestrictmeta') {
1.560     damieng  8244:             &setrestrictmeta($r);
1.414     droeschl 8245:         } elsif ($env{'form.action'} eq 'newoverview') {
1.568     raeburn  8246:             &newoverview($r,$parm_permission);
1.414     droeschl 8247:         } elsif ($env{'form.action'} eq 'setdefaults') {
1.560     damieng  8248:             &defaultsetter($r);
                   8249:         } elsif ($env{'form.action'} eq 'settable') {
1.568     raeburn  8250:             &assessparms($r,$parm_permission);
1.414     droeschl 8251:         } elsif ($env{'form.action'} eq 'parameterchangelog') {
1.568     raeburn  8252:             &parm_change_log($r,$parm_permission);
1.414     droeschl 8253:         } elsif ($env{'form.action'} eq 'cleanparameters') {
1.560     damieng  8254:             &clean_parameters($r);
1.414     droeschl 8255:         } elsif ($env{'form.action'} eq 'dateshift1') {
1.390     www      8256:             &date_shift_one($r);
1.414     droeschl 8257:         } elsif ($env{'form.action'} eq 'dateshift2') {
1.390     www      8258:             &date_shift_two($r);
1.446     bisitz   8259:         }
1.43      albertel 8260:     } else {
1.1       www      8261: # ----------------------------- Not in a course, or not allowed to modify parms
1.560     damieng  8262:         if ($exists) {
                   8263:             $env{'user.error.msg'}=
                   8264:             "/adm/parmset:opa:0:0:Cannot modify assessment parameters";
                   8265:         } else {
                   8266:             $env{'user.error.msg'}=
                   8267:             "/adm/parmset::0:1:Course environment gone, reinitialize the course";
                   8268:         }
                   8269:         return HTTP_NOT_ACCEPTABLE;
1.43      albertel 8270:     }
1.376     albertel 8271:     &reset_caches();
                   8272: 
1.43      albertel 8273:     return OK;
1.1       www      8274: }
                   8275: 
                   8276: 1;
                   8277: __END__
                   8278: 
                   8279: 

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