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

1.1       www         1: # The LearningOnline Network with CAPA
                      2: # Handler to set parameters for assessments
                      3: #
1.622   ! raeburn     4: # $Id: lonparmset.pm,v 1.621 2023/12/22 13:38:02 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.617     raeburn   332: use Text::Wrap();
1.416     jms       333: use LONCAPA qw(:DEFAULT :match);
                    334: 
                    335: 
1.560     damieng   336: ##################################################
                    337: # CONTENT AND PROBLEM SETTINGS HTML PAGE HEADER/FOOTER
                    338: ##################################################
                    339: 
                    340: # Page header
1.561     damieng   341: #
                    342: # @param {Apache2::RequestRec} $r - Apache request object
                    343: # @param {string} $mode - selected tab, 'parmset' for course and problem settings, or 'coursepref' for course settings
                    344: # @param {string} $crstype - course type ('Community' for community settings)
1.507     www       345: sub startSettingsScreen {
1.531     raeburn   346:     my ($r,$mode,$crstype)=@_;
1.507     www       347: 
1.531     raeburn   348:     my $tabtext = &mt('Course Settings');
                    349:     if ($crstype eq 'Community') {
                    350:         $tabtext = &mt('Community Settings');
                    351:     } 
1.507     www       352:     $r->print("\n".'<ul class="LC_TabContentBigger" id="main">');
                    353:     $r->print("\n".'<li'.($mode eq 'coursepref'?' class="active"':'').'><a href="/adm/courseprefs"><b>&nbsp;&nbsp;&nbsp;&nbsp;'.
1.531     raeburn   354:                                           $tabtext.
1.507     www       355:                                           '&nbsp;&nbsp;&nbsp;&nbsp;</b></a></li>');
                    356: 
1.523     raeburn   357:     $r->print("\n".'<li'.($mode eq 'parmset'?' class="active"':'').' id="tabbededitor"><a href="/adm/parmset"><b>'.
1.507     www       358:                                                                  &mt('Content and Problem Settings').'</b></a></li>');
                    359:     $r->print("\n".'</ul>'."\n");
1.523     raeburn   360:     $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       361: }
                    362: 
1.560     damieng   363: # Page footer
1.507     www       364: sub endSettingsScreen {
                    365:    my ($r)=@_;
                    366:    $r->print('</div></div></div>');
                    367: }
                    368: 
                    369: 
                    370: 
1.560     damieng   371: ##################################################
1.563     damieng   372: # (mostly) TABLE MODE
1.560     damieng   373: # (parmval is also used for the log of parameter changes)
                    374: ##################################################
                    375: 
1.566     damieng   376: # Calls parmval_by_symb, getting the symb from $id with &symbcache.
1.561     damieng   377: #
                    378: # @param {string} $what - part info and parameter name separated by a dot, e.g. '0.weight'
1.566     damieng   379: # @param {string} $id - resource id or map pc
1.561     damieng   380: # @param {string} $def - the resource's default value for this parameter
                    381: # @param {string} $uname - user name
                    382: # @param {string} $udom - user domain
                    383: # @param {string} $csec - section name
                    384: # @param {string} $cgroup - group name
                    385: # @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db)
                    386: # @returns {Array}
1.2       www       387: sub parmval {
1.275     raeburn   388:     my ($what,$id,$def,$uname,$udom,$csec,$cgroup,$courseopt)=@_;
                    389:     return &parmval_by_symb($what,&symbcache($id),$def,$uname,$udom,$csec,
                    390:                                                            $cgroup,$courseopt);
1.201     www       391: }
                    392: 
1.561     damieng   393: # Returns an array containing
                    394: # - the most specific level that is defined for that parameter (integer)
                    395: # - an array with the level as index and the parameter value as value (when defined)
                    396: #   (level 1 is the most specific and will have precedence)
                    397: #
                    398: # @param {string} $what - part info and parameter name separated by a dot, e.g. '0.weight'
1.566     damieng   399: # @param {string} $symb - resource symb or map src
1.561     damieng   400: # @param {string} $def - the resource's default value for this parameter
                    401: # @param {string} $uname - user name
                    402: # @param {string} $udom - user domain
                    403: # @param {string} $csec - section name
                    404: # @param {string} $cgroup - group name
                    405: # @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db)
                    406: # @returns {Array}
1.201     www       407: sub parmval_by_symb {
1.275     raeburn   408:     my ($what,$symb,$def,$uname,$udom,$csec,$cgroup,$courseopt)=@_;
1.200     www       409: 
1.352     albertel  410:     my $useropt;
                    411:     if ($uname ne '' && $udom ne '') {
1.561     damieng   412:         $useropt = &Apache::lonnet::get_userresdata($uname,$udom);
1.352     albertel  413:     }
1.200     www       414: 
1.8       www       415:     my $result='';
1.44      albertel  416:     my @outpar=();
1.2       www       417: # ----------------------------------------------------- Cascading lookup scheme
1.446     bisitz    418:     my $map=(&Apache::lonnet::decode_symb($symb))[0];
1.305     albertel  419:     $map = &Apache::lonnet::deversion($map);
1.561     damieng   420:     
                    421:     # NOTE: some of that code looks redondant with code in lonnavmaps::parmval_real,
                    422:     # any change should be reflected there.
                    423:     
1.201     www       424:     my $symbparm=$symb.'.'.$what;
1.556     raeburn   425:     my $recurseparm=$map.'___(rec).'.$what; 
1.201     www       426:     my $mapparm=$map.'___(all).'.$what;
1.10      www       427: 
1.269     raeburn   428:     my $grplevel=$env{'request.course.id'}.'.['.$cgroup.'].'.$what;
                    429:     my $grplevelr=$env{'request.course.id'}.'.['.$cgroup.'].'.$symbparm;
1.556     raeburn   430:     my $grpleveli=$env{'request.course.id'}.'.['.$cgroup.'].'.$recurseparm;
1.269     raeburn   431:     my $grplevelm=$env{'request.course.id'}.'.['.$cgroup.'].'.$mapparm;
                    432: 
1.190     albertel  433:     my $seclevel=$env{'request.course.id'}.'.['.$csec.'].'.$what;
                    434:     my $seclevelr=$env{'request.course.id'}.'.['.$csec.'].'.$symbparm;
1.556     raeburn   435:     my $secleveli=$env{'request.course.id'}.'.['.$csec.'].'.$recurseparm;
1.190     albertel  436:     my $seclevelm=$env{'request.course.id'}.'.['.$csec.'].'.$mapparm;
                    437: 
                    438:     my $courselevel=$env{'request.course.id'}.'.'.$what;
                    439:     my $courselevelr=$env{'request.course.id'}.'.'.$symbparm;
1.556     raeburn   440:     my $courseleveli=$env{'request.course.id'}.'.'.$recurseparm;
1.190     albertel  441:     my $courselevelm=$env{'request.course.id'}.'.'.$mapparm;
1.2       www       442: 
1.11      www       443: 
1.182     albertel  444: # --------------------------------------------------------- first, check course
1.11      www       445: 
1.561     damieng   446: # 18 - General Course
1.200     www       447:     if (defined($$courseopt{$courselevel})) {
1.556     raeburn   448:         $outpar[18]=$$courseopt{$courselevel};
                    449:         $result=18;
                    450:     }
                    451: 
1.561     damieng   452: # 17 - Map or Folder level in course (recursive) 
1.556     raeburn   453:     if (defined($$courseopt{$courseleveli})) {
                    454:         $outpar[17]=$$courseopt{$courseleveli};
                    455:         $result=17;
1.43      albertel  456:     }
1.11      www       457: 
1.561     damieng   458: # 16 - Map or Folder level in course (non-recursive)
1.200     www       459:     if (defined($$courseopt{$courselevelm})) {
1.556     raeburn   460:         $outpar[16]=$$courseopt{$courselevelm};
                    461:         $result=16;
1.43      albertel  462:     }
1.11      www       463: 
1.182     albertel  464: # ------------------------------------------------------- second, check default
                    465: 
1.561     damieng   466: # 15 - resource default
1.556     raeburn   467:     if (defined($def)) { $outpar[15]=$def; $result=15; }
1.182     albertel  468: 
                    469: # ------------------------------------------------------ third, check map parms
                    470: 
1.556     raeburn   471:     
1.561     damieng   472: # 14 - map default
1.376     albertel  473:     my $thisparm=&parmhash($symbparm);
1.556     raeburn   474:     if (defined($thisparm)) { $outpar[14]=$thisparm; $result=14; }
1.182     albertel  475: 
1.561     damieng   476: # 13 - resource level in course
1.200     www       477:     if (defined($$courseopt{$courselevelr})) {
1.556     raeburn   478:         $outpar[13]=$$courseopt{$courselevelr};
                    479:         $result=13;
1.43      albertel  480:     }
1.11      www       481: 
1.182     albertel  482: # ------------------------------------------------------ fourth, back to course
1.352     albertel  483:     if ($csec ne '') {
1.561     damieng   484: # 12 - General for section
1.200     www       485:         if (defined($$courseopt{$seclevel})) {
1.556     raeburn   486:             $outpar[12]=$$courseopt{$seclevel};
                    487:             $result=12;
                    488:         }
1.561     damieng   489: # 11 - Map or Folder level for section (recursive)
1.556     raeburn   490:         if (defined($$courseopt{$secleveli})) {
                    491:             $outpar[11]=$$courseopt{$secleveli};
                    492:             $result=11;
                    493:         }
1.561     damieng   494: # 10 - Map or Folder level for section (non-recursive)
1.200     www       495:         if (defined($$courseopt{$seclevelm})) {
1.556     raeburn   496:             $outpar[10]=$$courseopt{$seclevelm};
                    497:             $result=10;
                    498:         }
1.561     damieng   499: # 9 - resource level in section
1.200     www       500:         if (defined($$courseopt{$seclevelr})) {
1.556     raeburn   501:             $outpar[9]=$$courseopt{$seclevelr};
                    502:             $result=9;
                    503:         }
1.43      albertel  504:     }
1.275     raeburn   505: # ------------------------------------------------------ fifth, check course group
1.352     albertel  506:     if ($cgroup ne '') {
1.561     damieng   507: # 8 - General for group
1.269     raeburn   508:         if (defined($$courseopt{$grplevel})) {
1.556     raeburn   509:             $outpar[8]=$$courseopt{$grplevel};
                    510:             $result=8;
                    511:         }
1.561     damieng   512: # 7 - Map or Folder level for group (recursive)
1.556     raeburn   513:         if (defined($$courseopt{$grpleveli})) {
                    514:             $outpar[7]=$$courseopt{$grpleveli};
                    515:             $result=7;
1.269     raeburn   516:         }
1.561     damieng   517: # 6 - Map or Folder level for group (non-recursive)
1.269     raeburn   518:         if (defined($$courseopt{$grplevelm})) {
1.556     raeburn   519:             $outpar[6]=$$courseopt{$grplevelm};
                    520:             $result=6;
1.269     raeburn   521:         }
1.561     damieng   522: # 5 - resource level in group
1.269     raeburn   523:         if (defined($$courseopt{$grplevelr})) {
1.556     raeburn   524:             $outpar[5]=$$courseopt{$grplevelr};
                    525:             $result=5;
1.269     raeburn   526:         }
                    527:     }
1.11      www       528: 
1.556     raeburn   529: # ---------------------------------------------------------- sixth, check user
1.11      www       530: 
1.352     albertel  531:     if ($uname ne '') {
1.561     damieng   532: # 4 - General for specific student
                    533:         if (defined($$useropt{$courselevel})) {
                    534:             $outpar[4]=$$useropt{$courselevel};
                    535:             $result=4;
                    536:         }
1.556     raeburn   537: 
1.561     damieng   538: # 3 - Map or Folder level for specific student (recursive)
                    539:         if (defined($$useropt{$courseleveli})) {
                    540:             $outpar[3]=$$useropt{$courseleveli};
                    541:             $result=3;
                    542:         }
1.473     amueller  543: 
1.561     damieng   544: # 2 - Map or Folder level for specific student (non-recursive)
                    545:         if (defined($$useropt{$courselevelm})) {
                    546:             $outpar[2]=$$useropt{$courselevelm};
                    547:             $result=2;
                    548:         }
1.473     amueller  549: 
1.561     damieng   550: # 1 - resource level for specific student
                    551:         if (defined($$useropt{$courselevelr})) {
                    552:             $outpar[1]=$$useropt{$courselevelr};
                    553:             $result=1;
                    554:         }
1.43      albertel  555:     }
1.44      albertel  556:     return ($result,@outpar);
1.2       www       557: }
                    558: 
1.198     www       559: 
                    560: 
1.376     albertel  561: # --- Caches local to lonparmset
                    562: 
1.446     bisitz    563: 
1.561     damieng   564: # Reset lonparmset caches (called at the beginning and end of the handler).
1.376     albertel  565: sub reset_caches {
                    566:     &resetparmhash();
                    567:     &resetsymbcache();
                    568:     &resetrulescache();
1.203     www       569: }
                    570: 
1.561     damieng   571: # cache for map parameters, stored temporarily in $env{'request.course.fn'}_parms.db
                    572: # (these parameters come from param elements in .sequence files created with the advanced RAT)
1.376     albertel  573: {
1.561     damieng   574:     my $parmhashid; # course identifier, to initialize the cache only once for a course
                    575:     my %parmhash; # the parameter cache
                    576:     # reset map parameter hash
1.376     albertel  577:     sub resetparmhash {
1.560     damieng   578:         undef($parmhashid);
                    579:         undef(%parmhash);
1.376     albertel  580:     }
1.446     bisitz    581: 
1.561     damieng   582:     # dump the _parms.db database into %parmhash
1.376     albertel  583:     sub cacheparmhash {
1.560     damieng   584:         if ($parmhashid eq  $env{'request.course.fn'}) { return; }
                    585:         my %parmhashfile;
                    586:         if (tie(%parmhashfile,'GDBM_File',
                    587:             $env{'request.course.fn'}.'_parms.db',&GDBM_READER(),0640)) {
                    588:             %parmhash=%parmhashfile;
                    589:             untie(%parmhashfile);
                    590:             $parmhashid=$env{'request.course.fn'};
                    591:         }
1.201     www       592:     }
1.446     bisitz    593: 
1.561     damieng   594:     # returns a parameter value for an identifier symb.parts.parameter, using the map parameter cache
1.376     albertel  595:     sub parmhash {
1.560     damieng   596:         my ($id) = @_;
                    597:         &cacheparmhash();
                    598:         return $parmhash{$id};
1.376     albertel  599:     }
1.560     damieng   600: }
1.376     albertel  601: 
1.566     damieng   602: # cache resource id or map pc -> resource symb or map src, using lonnavmaps to find association
1.446     bisitz    603: {
1.561     damieng   604:     my $symbsid; # course identifier, to initialize the cache only once for a course
                    605:     my %symbs; # hash id->symb
                    606:     # reset the id->symb cache
1.376     albertel  607:     sub resetsymbcache {
1.560     damieng   608:         undef($symbsid);
                    609:         undef(%symbs);
1.376     albertel  610:     }
1.446     bisitz    611: 
1.566     damieng   612:     # returns the resource symb or map src corresponding to a resource id or map pc
                    613:     # (using lonnavmaps and a cache)
1.376     albertel  614:     sub symbcache {
1.560     damieng   615:         my $id=shift;
                    616:         if ($symbsid ne $env{'request.course.id'}) {
                    617:             undef(%symbs);
                    618:         }
                    619:         if (!$symbs{$id}) {
                    620:             my $navmap = Apache::lonnavmaps::navmap->new();
                    621:             if ($id=~/\./) {
                    622:                 my $resource=$navmap->getById($id);
                    623:                 $symbs{$id}=$resource->symb();
                    624:             } else {
                    625:                 my $resource=$navmap->getByMapPc($id);
                    626:                 $symbs{$id}=&Apache::lonnet::declutter($resource->src());
                    627:             }
                    628:             $symbsid=$env{'request.course.id'};
1.473     amueller  629:         }
1.560     damieng   630:         return $symbs{$id};
1.473     amueller  631:     }
1.560     damieng   632: }
1.201     www       633: 
1.561     damieng   634: # cache for parameter default actions (stored in parmdefactions.db)
1.446     bisitz    635: {
1.561     damieng   636:     my $rulesid; # course identifier, to initialize the cache only once for a course
                    637:     my %rules; # parameter default actions hash
1.376     albertel  638:     sub resetrulescache {
1.560     damieng   639:         undef($rulesid);
                    640:         undef(%rules);
1.376     albertel  641:     }
1.446     bisitz    642: 
1.561     damieng   643:     # returns the value for a given key in the parameter default action hash
1.376     albertel  644:     sub rulescache {
1.560     damieng   645:         my $id=shift;
                    646:         if ($rulesid ne $env{'request.course.id'}
                    647:             && !defined($rules{$id})) {
                    648:             my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                    649:             my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
                    650:             %rules=&Apache::lonnet::dump('parmdefactions',$dom,$crs);
                    651:             $rulesid=$env{'request.course.id'};
                    652:         }
                    653:         return $rules{$id};
1.221     www       654:     }
                    655: }
                    656: 
1.416     jms       657: 
1.561     damieng   658: # Returns the values of the parameter type default action
                    659: # "default value when manually setting".
                    660: # If none is defined, ('','','','','') is returned.
                    661: #
                    662: # @param {string} $type - parameter type
                    663: # @returns {Array<string>} - (hours, min, sec, value)
1.229     www       664: sub preset_defaults {
                    665:     my $type=shift;
                    666:     if (&rulescache($type.'_action') eq 'default') {
1.560     damieng   667:         # yes, there is something
                    668:         return (&rulescache($type.'_hours'),
                    669:             &rulescache($type.'_min'),
                    670:             &rulescache($type.'_sec'),
                    671:             &rulescache($type.'_value'));
1.229     www       672:     } else {
1.560     damieng   673:         # nothing there or something else
                    674:         return ('','','','','');
1.229     www       675:     }
                    676: }
                    677: 
1.416     jms       678: 
1.561     damieng   679: # Checks that a date is after enrollment start date and before
                    680: # enrollment end date.
                    681: # Returns HTML with a warning if it is not, or the empty string otherwise.
                    682: # This is used by both overview and table modes.
                    683: #
                    684: # @param {integer} $checkdate - the date to check.
                    685: # @returns {string} - HTML possibly containing a localized warning message.
1.277     www       686: sub date_sanity_info {
                    687:    my $checkdate=shift;
                    688:    unless ($checkdate) { return ''; }
                    689:    my $result='';
                    690:    my $crsprefix='course.'.$env{'request.course.id'}.'.';
                    691:    if ($env{$crsprefix.'default_enrollment_end_date'}) {
                    692:       if ($checkdate>$env{$crsprefix.'default_enrollment_end_date'}) {
1.413     bisitz    693:          $result.='<div class="LC_warning">'
                    694:                  .&mt('After course enrollment end!')
                    695:                  .'</div>';
1.277     www       696:       }
                    697:    }
                    698:    if ($env{$crsprefix.'default_enrollment_start_date'}) {
                    699:       if ($checkdate<$env{$crsprefix.'default_enrollment_start_date'}) {
1.413     bisitz    700:          $result.='<div class="LC_warning">'
                    701:                  .&mt('Before course enrollment start!')
                    702:                  .'</div>';
1.277     www       703:       }
                    704:    }
1.413     bisitz    705: # Preparation for additional warnings about dates in the past/future.
                    706: # An improved, more context sensitive version is recommended,
                    707: # e.g. warn for due and answer dates which are defined before the corresponding open date, etc.
                    708: #   if ($checkdate<time) {
                    709: #      $result.='<div class="LC_info">'
                    710: #              .'('.&mt('in the past').')'
                    711: #              .'</div>';
                    712: #      }
                    713: #   if ($checkdate>time) {
                    714: #      $result.='<div class="LC_info">'
                    715: #              .'('.&mt('in the future').')'
                    716: #              .'</div>';
                    717: #      }
1.277     www       718:    return $result;
                    719: }
1.561     damieng   720: 
                    721: 
                    722: # Store a parameter value and type by ID, also triggering more parameter changes based on parameter default actions.
1.186     www       723: #
1.566     damieng   724: # @param {string} $sresid - resource id or map pc
1.565     damieng   725: # @param {string} $spnam - part info and parameter name separated by a dot or underscore, e.g. '0.weight'
1.561     damieng   726: # @param {integer} $snum - level
                    727: # @param {string} $nval - new value
                    728: # @param {string} $ntype - new type
                    729: # @param {string} $uname - username
                    730: # @param {string} $udom - userdomain
                    731: # @param {string} $csec - section name
                    732: # @param {string} $cgroup - group name
1.186     www       733: sub storeparm {
1.269     raeburn   734:     my ($sresid,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$cgroup)=@_;
1.275     raeburn   735:     &storeparm_by_symb(&symbcache($sresid),$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,'',$cgroup);
1.197     www       736: }
                    737: 
1.561     damieng   738: my %recstack; # hash parameter name -> 1 when a parameter was used before in a recursive call to storeparm_by_symb
                    739: 
                    740: # Store a parameter value and type by symb, also triggering more parameter changes based on parameter default actions.
                    741: # Uses storeparm_by_symb_inner to actually store the parameter, ignoring any returned error.
                    742: #
1.566     damieng   743: # @param {string} $symb - resource symb or map src
1.565     damieng   744: # @param {string} $spnam - part info and parameter name separated by a dot or underscore, e.g. '0.weight'
1.561     damieng   745: # @param {integer} $snum - level
                    746: # @param {string} $nval - new value
                    747: # @param {string} $ntype - new type
                    748: # @param {string} $uname - username
                    749: # @param {string} $udom - userdomain
                    750: # @param {string} $csec - section name
                    751: # @param {boolean} $recflag - should be true for recursive calls to storeparm_by_symb, false otherwise
                    752: # @param {string} $cgroup - group name
1.197     www       753: sub storeparm_by_symb {
1.275     raeburn   754:     my ($symb,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$recflag,$cgroup)=@_;
1.226     www       755:     unless ($recflag) {
1.560     damieng   756:         # first time call
                    757:         %recstack=();
                    758:         $recflag=1;
1.226     www       759:     }
1.560     damieng   760:     # store parameter
1.226     www       761:     &storeparm_by_symb_inner
1.473     amueller  762:     ($symb,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$cgroup);
1.560     damieng   763:     # don't do anything if parameter was reset
1.266     www       764:     unless ($nval) { return; }
1.226     www       765:     my ($prefix,$parm)=($spnam=~/^(.*[\_\.])([^\_\.]+)$/);
1.560     damieng   766:     # remember that this was set
1.226     www       767:     $recstack{$parm}=1;
1.560     damieng   768:     # what does this trigger?
1.226     www       769:     foreach my $triggered (split(/\:/,&rulescache($parm.'_triggers'))) {
1.560     damieng   770:         # don't backfire
                    771:         unless ((!$triggered) || ($recstack{$triggered})) {
                    772:             my $action=&rulescache($triggered.'_action');
                    773:             my ($whichaction,$whichparm)=($action=~/^(.*\_)([^\_]+)$/);
                    774:             # set triggered parameter on same level
                    775:             my $newspnam=$prefix.$triggered;
                    776:             my $newvalue='';
                    777:             my $active=1;
                    778:             if ($action=~/^when\_setting/) {
                    779:             # are there restrictions?
                    780:                 if (&rulescache($triggered.'_triggervalue')=~/\w/) {
                    781:                     $active=0;
1.565     damieng   782:                     foreach my $possiblevalue (split(/\s*\,\s*/,&rulescache($triggered.'_triggervalue'))) {
1.560     damieng   783:                         if (lc($possiblevalue) eq lc($nval)) { $active=1; }
                    784:                     }
                    785:                 }
                    786:                 $newvalue=&rulescache($triggered.'_value');
                    787:             } else {
                    788:                 my $totalsecs=((&rulescache($triggered.'_days')*24+&rulescache($triggered.'_hours'))*60+&rulescache($triggered.'_min'))*60+&rulescache($triggered.'_sec');
                    789:                 if ($action=~/^later\_than/) {
                    790:                     $newvalue=$nval+$totalsecs;
                    791:                 } else {
                    792:                     $newvalue=$nval-$totalsecs;
                    793:                 }
                    794:             }
                    795:             if ($active) {
                    796:                 &storeparm_by_symb($symb,$newspnam,$snum,$newvalue,&rulescache($triggered.'_type'),
                    797:                         $uname,$udom,$csec,$recflag,$cgroup);
                    798:             }
                    799:         }
1.226     www       800:     }
                    801:     return '';
                    802: }
                    803: 
1.561     damieng   804: # Adds all given arguments to the course parameter log.
                    805: # @returns {string} - the answer to the lonnet query.
1.293     www       806: sub log_parmset {
1.525     raeburn   807:     return &Apache::lonnet::write_log('course','parameterlog',@_);
1.284     www       808: }
                    809: 
1.561     damieng   810: # Store a parameter value and type by symb, without using the parameter default actions.
                    811: # Expire related sheets.
                    812: #
1.566     damieng   813: # @param {string} $symb - resource symb or map src
1.561     damieng   814: # @param {string} $spnam - part info and parameter name separated by a dot, e.g. '0.weight'
                    815: # @param {integer} $snum - level
                    816: # @param {string} $nval - new value
                    817: # @param {string} $ntype - new type
                    818: # @param {string} $uname - username
                    819: # @param {string} $udom - userdomain
                    820: # @param {string} $csec - section name
                    821: # @param {string} $cgroup - group name
                    822: # @returns {string} - HTML code with an error message if the parameter could not be stored.
1.226     www       823: sub storeparm_by_symb_inner {
1.197     www       824: # ---------------------------------------------------------- Get symb, map, etc
1.269     raeburn   825:     my ($symb,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$cgroup)=@_;
1.197     www       826: # ---------------------------------------------------------- Construct prefixes
1.186     www       827:     $spnam=~s/\_([^\_]+)$/\.$1/;
1.446     bisitz    828:     my $map=(&Apache::lonnet::decode_symb($symb))[0];
1.305     albertel  829:     $map = &Apache::lonnet::deversion($map);
                    830: 
1.197     www       831:     my $symbparm=$symb.'.'.$spnam;
1.556     raeburn   832:     my $recurseparm=$map.'___(rec).'.$spnam;
1.197     www       833:     my $mapparm=$map.'___(all).'.$spnam;
                    834: 
1.269     raeburn   835:     my $grplevel=$env{'request.course.id'}.'.['.$cgroup.'].'.$spnam;
                    836:     my $grplevelr=$env{'request.course.id'}.'.['.$cgroup.'].'.$symbparm;
1.556     raeburn   837:     my $grpleveli=$env{'request.course.id'}.'.['.$cgroup.'].'.$recurseparm;
1.269     raeburn   838:     my $grplevelm=$env{'request.course.id'}.'.['.$cgroup.'].'.$mapparm;
                    839: 
1.190     albertel  840:     my $seclevel=$env{'request.course.id'}.'.['.$csec.'].'.$spnam;
                    841:     my $seclevelr=$env{'request.course.id'}.'.['.$csec.'].'.$symbparm;
1.556     raeburn   842:     my $secleveli=$env{'request.course.id'}.'.['.$csec.'].'.$recurseparm;
1.190     albertel  843:     my $seclevelm=$env{'request.course.id'}.'.['.$csec.'].'.$mapparm;
1.446     bisitz    844: 
1.190     albertel  845:     my $courselevel=$env{'request.course.id'}.'.'.$spnam;
                    846:     my $courselevelr=$env{'request.course.id'}.'.'.$symbparm;
1.556     raeburn   847:     my $courseleveli=$env{'request.course.id'}.'.'.$recurseparm;
1.190     albertel  848:     my $courselevelm=$env{'request.course.id'}.'.'.$mapparm;
1.446     bisitz    849: 
1.186     www       850:     my $storeunder='';
1.578     raeburn   851:     my $possreplace='';
1.556     raeburn   852:     if (($snum==18) || ($snum==4)) { $storeunder=$courselevel; }
1.578     raeburn   853:     if (($snum==17) || ($snum==3)) { 
                    854:         $storeunder=$courseleveli;
                    855:         $possreplace=$courselevelm; 
                    856:     } 
                    857:     if (($snum==16) || ($snum==2)) { 
                    858:         $storeunder=$courselevelm;
                    859:         $possreplace=$courseleveli;
                    860:     }
1.556     raeburn   861:     if (($snum==13) || ($snum==1)) { $storeunder=$courselevelr; }
                    862:     if ($snum==12) { $storeunder=$seclevel; }
1.578     raeburn   863:     if ($snum==11) { 
                    864:         $storeunder=$secleveli;
                    865:         $possreplace=$seclevelm; 
                    866:     }
                    867:     if ($snum==10) { 
                    868:         $storeunder=$seclevelm;
                    869:         $possreplace=$secleveli;
                    870:     }
1.556     raeburn   871:     if ($snum==9) { $storeunder=$seclevelr; }
                    872:     if ($snum==8) { $storeunder=$grplevel; }
1.578     raeburn   873:     if ($snum==7) { 
                    874:         $storeunder=$grpleveli;
                    875:         $possreplace=$grplevelm;
                    876:     }
                    877:     if ($snum==6) {
                    878:         $storeunder=$grplevelm;
                    879:         $possreplace=$grpleveli;
                    880:     }
1.556     raeburn   881:     if ($snum==5) { $storeunder=$grplevelr; }
1.269     raeburn   882: 
1.446     bisitz    883: 
1.186     www       884:     my $delete;
                    885:     if ($nval eq '') { $delete=1;}
                    886:     my %storecontent = ($storeunder         => $nval,
1.473     amueller  887:             $storeunder.'.type' => $ntype);
1.186     www       888:     my $reply='';
1.560     damieng   889:     
1.556     raeburn   890:     if ($snum>4) {
1.186     www       891: # ---------------------------------------------------------------- Store Course
                    892: #
1.560     damieng   893:         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                    894:         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                    895:         # Expire sheets
                    896:         &Apache::lonnet::expirespread('','','studentcalc');
                    897:         if (($snum==13) || ($snum==9) || ($snum==5)) {
                    898:             &Apache::lonnet::expirespread('','','assesscalc',$symb);
1.578     raeburn   899:         } elsif (($snum==17) || ($snum==16) || ($snum==11) || ($snum==10) || ($snum==7) || ($snum==6)) {
1.560     damieng   900:             &Apache::lonnet::expirespread('','','assesscalc',$map);
                    901:         } else {
                    902:             &Apache::lonnet::expirespread('','','assesscalc');
                    903:         }
                    904:         # Store parameter
                    905:         if ($delete) {
                    906:             $reply=&Apache::lonnet::del
                    907:             ('resourcedata',[keys(%storecontent)],$cdom,$cnum);
                    908:                 &log_parmset(\%storecontent,1);
                    909:         } else {
                    910:             $reply=&Apache::lonnet::cput
                    911:             ('resourcedata',\%storecontent,$cdom,$cnum);
                    912:             &log_parmset(\%storecontent);
1.578     raeburn   913:             if ($possreplace) {
                    914:                 my $resdata = &Apache::lonnet::get_courseresdata($cnum,$cdom);
                    915:                 if (ref($resdata) eq 'HASH') {
                    916:                     if (exists($resdata->{$possreplace})) {
                    917:                         if (&Apache::lonnet::del
                    918:                             ('resourcedata',[$possreplace,$possreplace.'.type'],$cdom,$cnum) eq 'ok') {
                    919:                             &log_parmset({$possreplace => '', $possreplace.'.type' => $ntype},1);   
                    920:                         }
                    921:                     }
                    922:                 }
                    923:             }
1.560     damieng   924:         }
                    925:         &Apache::lonnet::devalidatecourseresdata($cnum,$cdom);
1.186     www       926:     } else {
                    927: # ------------------------------------------------------------------ Store User
                    928: #
1.560     damieng   929:         # Expire sheets
                    930:         &Apache::lonnet::expirespread($uname,$udom,'studentcalc');
                    931:         if ($snum==1) {
                    932:             &Apache::lonnet::expirespread
                    933:             ($uname,$udom,'assesscalc',$symb);
1.578     raeburn   934:         } elsif (($snum==2) || ($snum==3)) {
1.560     damieng   935:             &Apache::lonnet::expirespread
                    936:             ($uname,$udom,'assesscalc',$map);
                    937:         } else {
                    938:             &Apache::lonnet::expirespread($uname,$udom,'assesscalc');
                    939:         }
                    940:         # Store parameter
                    941:         if ($delete) {
                    942:             $reply=&Apache::lonnet::del
                    943:             ('resourcedata',[keys(%storecontent)],$udom,$uname);
                    944:             &log_parmset(\%storecontent,1,$uname,$udom);
                    945:         } else {
                    946:             $reply=&Apache::lonnet::cput
                    947:             ('resourcedata',\%storecontent,$udom,$uname);
                    948:             &log_parmset(\%storecontent,0,$uname,$udom);
1.578     raeburn   949:             if ($possreplace) {
                    950:                 my $resdata = &Apache::lonnet::get_userresdata($uname,$udom);
                    951:                 if (ref($resdata) eq 'HASH') {
                    952:                     if (exists($resdata->{$possreplace})) {
                    953:                         if (&Apache::lonnet::del
                    954:                             ('resourcedata',[$possreplace,$possreplace.'.type'],$udom,$uname) eq 'ok') {
                    955:                             &log_parmset({$possreplace => '',$possreplace.'.type' => $ntype},1,
                    956:                                           $uname,$udom);
                    957:                         }
                    958:                     }
                    959:                 }
                    960:             }
1.560     damieng   961:         }
                    962:         &Apache::lonnet::devalidateuserresdata($uname,$udom);
1.186     www       963:     }
1.446     bisitz    964: 
1.186     www       965:     if ($reply=~/^error\:(.*)/) {
1.560     damieng   966:         return "<span class=\"LC_error\">Write Error: $1</span>";
1.186     www       967:     }
                    968:     return '';
                    969: }
                    970: 
1.9       www       971: 
1.561     damieng   972: # Returns HTML with the value of the given parameter,
                    973: # using a readable format for dates, and
                    974: # a warning if there is a problem with a date.
                    975: # Used by table mode.
                    976: # Returns HTML for the editmap.png image if no value is defined and $editable is true.
                    977: #
                    978: # @param {string} $value - the parameter value
                    979: # @param {string} $type - the parameter type
                    980: # @param {boolean} $editable - Set to true to get an icon when no value is defined.
1.9       www       981: sub valout {
1.600     raeburn   982:     my ($value,$type,$editable)=@_;
1.59      matthew   983:     my $result = '';
                    984:     # Values of zero are valid.
                    985:     if (! $value && $value ne '0') {
1.528     bisitz    986:         if ($editable) {
                    987:             $result =
                    988:                 '<img src="/res/adm/pages/editmap.png"'
                    989:                .' alt="'.&mt('Change').'"'
1.539     raeburn   990:                .' title="'.&mt('Change').'" style="border:0;" />';
1.528     bisitz    991:         } else {
                    992:             $result='&nbsp;';
                    993:         }
1.59      matthew   994:     } else {
1.622   ! raeburn   995:         if (($type eq 'date_interval') || ($type eq 'string_grace')) {
        !           996:             if ($type eq 'string_grace') {
        !           997:                 my @items;
        !           998:                 if ($value =~ /,/) {
        !           999:                     @items = split(/,/,$value);
1.558     raeburn  1000:                 } else {
1.622   ! raeburn  1001:                     @items = ($value);
        !          1002:                 }
        !          1003:                 foreach my $item (@items) {
        !          1004:                     if ($item =~ /^\d+:(0|1)\.?\d*:(0|1)$/) {
        !          1005:                         my ($totalsecs,$fraction,$grad) = split(/:/,$item);
        !          1006:                         $result .= &interval_to_humanstr($totalsecs);
        !          1007:                         if (($fraction >=0) && ($fraction <=1)) {
        !          1008:                             $result .= '&nbsp;|&nbsp;'.$fraction.'&nbsp;'.&mt('pts');
        !          1009:                             if ($grad == 1) {
        !          1010:                                 $result .= '&nbsp;('.&mt('gradual').')';
        !          1011:                             }
        !          1012:                         }
        !          1013:                         $result .= ', ';
        !          1014:                     }
        !          1015:                 }
        !          1016:                 $result =~ s/, $//;
        !          1017:             } else {
        !          1018:                 my ($totalsecs,$donesuffix) = split(/_/,$value,2);
        !          1019:                 $result = &interval_to_humanstr($totalsecs);
        !          1020:                 my ($usesdone,$donebuttontext,$proctor,$secretkey);
        !          1021:                 if ($donesuffix =~ /^done\:([^\:]+)\:(.*)$/) {
        !          1022:                     $donebuttontext = $1;
        !          1023:                     (undef,$proctor,$secretkey) = split(/_/,$2);
        !          1024:                     $usesdone = 'done';
        !          1025:                 } elsif ($donesuffix =~ /^done(|_.+)$/) {
        !          1026:                     $donebuttontext = &mt('Done');
        !          1027:                     ($usesdone,$proctor,$secretkey) = split(/_/,$donesuffix);
        !          1028:                 }
        !          1029:                 if ($usesdone eq 'done') {
        !          1030:                     if ($secretkey) {
        !          1031:                         $result .= ' '.&mt('+ "[_1]" with proctor key: [_2]',$donebuttontext,$secretkey);
        !          1032:                     } else {
        !          1033:                         $result .= ' + "'.$donebuttontext.'"';
        !          1034:                     }
1.559     raeburn  1035:                 }
1.554     raeburn  1036:             }
1.213     www      1037:         } elsif (&isdateparm($type)) {
1.361     albertel 1038:             $result = &Apache::lonlocal::locallocaltime($value).
1.560     damieng  1039:                 &date_sanity_info($value);
1.59      matthew  1040:         } else {
                   1041:             $result = $value;
1.517     www      1042:             $result=~s/\,/\, /gs;
1.560     damieng  1043:             $result = &HTML::Entities::encode($result,'"<>&');
1.59      matthew  1044:         }
                   1045:     }
                   1046:     return $result;
1.9       www      1047: }
                   1048: 
1.622   ! raeburn  1049: sub interval_to_humanstr {
        !          1050:     my ($totalsecs) = @_;
        !          1051:     my ($sec,$min,$hour,$mday,$mon,$year)=gmtime($totalsecs);
        !          1052:     my @timer;
        !          1053:     $year=$year-70;
        !          1054:     $mday--;
        !          1055:     if ($year) {
        !          1056:         push(@timer,&mt('[quant,_1,yr]',$year));
        !          1057:     }
        !          1058:     if ($mon) {
        !          1059:         push(@timer,&mt('[quant,_1,mth]',$mon));
        !          1060:     }
        !          1061:     if ($mday) {
        !          1062:         push(@timer,&mt('[quant,_1,day]',$mday));
        !          1063:     }
        !          1064:     if ($hour) {
        !          1065:         push(@timer,&mt('[quant,_1,hr]',$hour));
        !          1066:     }
        !          1067:     if ($min) {
        !          1068:         push(@timer,&mt('[quant,_1,min]',$min));
        !          1069:     }
        !          1070:     if ($sec) {
        !          1071:         push(@timer,&mt('[quant,_1,sec]',$sec));
        !          1072:     }
        !          1073:     if (!@timer) { # Special case: all entries 0 -> display "0 secs" intead of empty field to keep this field editable
        !          1074:         push(@timer,&mt('[quant,_1,sec]',0));
        !          1075:     }
        !          1076:     return '<span style="white-space:nowrap">'.join('</span>, <span style="white-space:nowrap">',@timer).'</span>';
        !          1077: }
1.59      matthew  1078: 
1.561     damieng  1079: # Returns HTML containing a link on a parameter value, for table mode.
                   1080: # The link uses the javascript function 'pjump'.
                   1081: #
                   1082: # @param {string} $type - parameter type
                   1083: # @param {string} $dis - dialog title for editing the parameter value and type
                   1084: # @param {string} $value - parameter value
                   1085: # @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.
                   1086: # @param {string} $return - prefix for the name of the form and field names that will be used to submit the form ('parmform.pres')
                   1087: # @param {string} $call - javascript function to call to submit the form ('psub')
1.588     raeburn  1088: # @param {boolean} $recursive - true if link is for a map/folder where parameter is currently set to be recursive.
                   1089: # @param {string} $extra - optional additional information to send as tenth arg in call to javascript pjump function.
1.5       www      1090: sub plink {
1.588     raeburn  1091:     my ($type,$dis,$value,$marker,$return,$call,$recursive,$extra)=@_;
1.23      www      1092:     my $winvalue=$value;
                   1093:     unless ($winvalue) {
1.592     raeburn  1094:         if (&isdateparm($type) || (&is_specialstring($type))) {
1.190     albertel 1095:             $winvalue=$env{'form.recent_'.$type};
1.591     raeburn  1096:         } elsif ($type eq 'string_yesno') {
                   1097:             if ($env{'form.recent_string'} =~ /^(yes|no)$/i) {
                   1098:                 $winvalue=$env{'form.recent_string'};
                   1099:             }
1.23      www      1100:         } else {
1.190     albertel 1101:             $winvalue=$env{'form.recent_'.(split(/\_/,$type))[0]};
1.23      www      1102:         }
                   1103:     }
1.229     www      1104:     my ($parmname)=((split(/\&/,$marker))[1]=~/\_([^\_]+)$/);
                   1105:     my ($hour,$min,$sec,$val)=&preset_defaults($parmname);
                   1106:     unless (defined($winvalue)) { $winvalue=$val; }
1.593     raeburn  1107:     my $valout = &valout($value,$type,1);
1.429     raeburn  1108:     my $unencmarker = $marker;
1.378     albertel 1109:     foreach my $item (\$type, \$dis, \$winvalue, \$marker, \$return, \$call,
1.588     raeburn  1110:               \$hour, \$min, \$sec, \$extra) {
1.560     damieng  1111:         $$item = &HTML::Entities::encode($$item,'"<>&');
                   1112:         $$item =~ s/\'/\\\'/g;
1.378     albertel 1113:     }
1.429     raeburn  1114:     return '<table width="100%"><tr valign="top" align="right"><td><a name="'.$unencmarker.'" /></td></tr><tr><td align="center">'.
1.473     amueller 1115:     '<a href="javascript:pjump('."'".$type."','".$dis."','".$winvalue."','"
1.588     raeburn  1116:         .$marker."','".$return."','".$call."','".$hour."','".$min."','".$sec."','".$extra."'".');">'.
1.578     raeburn  1117:         $valout.'</a></td></tr>'.($recursive?'<tr><td align="center" class="LC_parm_recursive">'.
                   1118:                                               &mt('recursive').'</td></tr>' : '').'</table>';
                   1119: 
1.5       www      1120: }
                   1121: 
1.561     damieng  1122: # Javascript for table mode.
1.280     albertel 1123: sub page_js {
                   1124: 
1.81      www      1125:     my $selscript=&Apache::loncommon::studentbrowser_javascript();
1.88      matthew  1126:     my $pjump_def = &Apache::lonhtmlcommon::pjump_javascript_definition();
1.280     albertel 1127: 
                   1128:     return(<<ENDJS);
                   1129: <script type="text/javascript">
1.454     bisitz   1130: // <![CDATA[
1.44      albertel 1131: 
1.88      matthew  1132:     $pjump_def
1.44      albertel 1133: 
                   1134:     function psub() {
1.591     raeburn  1135:         var specstring = /^string_!(yesno|any)/i;
1.44      albertel 1136:         if (document.parmform.pres_marker.value!='') {
                   1137:             document.parmform.action+='#'+document.parmform.pres_marker.value;
                   1138:             var typedef=new Array();
                   1139:             typedef=document.parmform.pres_type.value.split('_');
1.562     damieng  1140:             if (document.parmform.pres_type.value!='') {
1.589     raeburn  1141:                 if ((typedef[0]=='date') || 
1.591     raeburn  1142:                     (specstring.test(document.parmform.pres_type.value)))  {
1.562     damieng  1143:                     eval('document.parmform.recent_'+
                   1144:                         document.parmform.pres_type.value+
                   1145:                         '.value=document.parmform.pres_value.value;');
                   1146:                 } else {
                   1147:                     eval('document.parmform.recent_'+typedef[0]+
                   1148:                         '.value=document.parmform.pres_value.value;');
                   1149:                 }
1.44      albertel 1150:             }
                   1151:             document.parmform.submit();
                   1152:         } else {
                   1153:             document.parmform.pres_value.value='';
                   1154:             document.parmform.pres_marker.value='';
                   1155:         }
                   1156:     }
                   1157: 
1.57      albertel 1158:     function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
                   1159:         var options = "width=" + w + ",height=" + h + ",";
                   1160:         options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
                   1161:         options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
                   1162:         var newWin = window.open(url, wdwName, options);
                   1163:         newWin.focus();
                   1164:     }
1.523     raeburn  1165: 
1.454     bisitz   1166: // ]]>
1.523     raeburn  1167: 
1.44      albertel 1168: </script>
1.81      www      1169: $selscript
1.280     albertel 1170: ENDJS
                   1171: 
                   1172: }
1.507     www      1173: 
1.561     damieng  1174: # Javascript to show or hide the map selection (function showHide_courseContent),
                   1175: # for table and overview modes.
1.523     raeburn  1176: sub showhide_js {
                   1177:     return <<"COURSECONTENTSCRIPT";
                   1178: 
                   1179: function showHide_courseContent() {
                   1180:     var parmlevValue=document.getElementById("parmlev").value;
                   1181:     if (parmlevValue == 'general') {
                   1182:         document.getElementById('mapmenu').style.display="none";
                   1183:     } else {
                   1184:         if ((parmlevValue == "full") || (parmlevValue == "map")) {
                   1185:             document.getElementById('mapmenu').style.display ="";
                   1186:         } else {
                   1187:             document.getElementById('mapmenu').style.display="none";
                   1188:         }
                   1189:     }
                   1190:     return;
                   1191: }
                   1192: 
                   1193: COURSECONTENTSCRIPT
                   1194: }
                   1195: 
1.561     damieng  1196: # Javascript functions showHideLenient and toggleParmTextbox, for overview mode
1.549     raeburn  1197: sub toggleparmtextbox_js {
                   1198:     return <<"ENDSCRIPT";
                   1199: 
                   1200: if (!document.getElementsByClassName) {
                   1201:     function getElementsByClassName(node, classname) {
                   1202:         var a = [];
                   1203:         var re = new RegExp('(^| )'+classname+'( |$)');
                   1204:         var els = node.getElementsByTagName("*");
                   1205:         for(var i=0,j=els.length; i<j; i++)
                   1206:             if(re.test(els[i].className))a.push(els[i]);
                   1207:         return a;
                   1208:     }
                   1209: }
                   1210: 
                   1211: function showHideLenient() {
                   1212:     var lenients;
                   1213:     var setRegExp = /^set_/;
                   1214:     if (document.getElementsByClassName) {
                   1215:         lenients = document.getElementsByClassName('LC_lenient_radio');
                   1216:     } else {
                   1217:         lenients = getElementsByClassName(document.body,'LC_lenient_radio');
                   1218:     }
                   1219:     if (lenients != 'undefined') {
                   1220:         for (var i=0; i<lenients.length; i++) {
                   1221:             if (lenients[i].checked) {
                   1222:                 if (lenients[i].value == 'weighted') {
                   1223:                     if (setRegExp.test(lenients[i].name)) {
                   1224:                         var identifier = lenients[i].name.replace(setRegExp,'');
                   1225:                         toggleParmTextbox(document.parmform,identifier);
                   1226:                     }
                   1227:                 }
                   1228:             }
                   1229:         }
                   1230:     }
                   1231:     return;
                   1232: }
                   1233: 
                   1234: function toggleParmTextbox(form,key) {
                   1235:     var divfortext = document.getElementById('LC_parmtext_'+key);
                   1236:     if (divfortext) {
                   1237:         var caller = form.elements['set_'+key];
                   1238:         if (caller.length) {
                   1239:             for (i=0; i<caller.length; i++) {
                   1240:                 if (caller[i].checked) {
                   1241:                     if (caller[i].value == 'weighted') {
                   1242:                         divfortext.style.display = 'inline';
                   1243:                     } else {
                   1244:                         divfortext.style.display = 'none';
                   1245:                     }
                   1246:                 }
                   1247:             }
                   1248:         }
                   1249:     }
                   1250:     return;
                   1251: }
                   1252: 
                   1253: ENDSCRIPT
                   1254: }
                   1255: 
1.561     damieng  1256: # Javascript function validateParms, for overview mode
1.549     raeburn  1257: sub validateparms_js {
                   1258:     return <<'ENDSCRIPT';
                   1259: 
                   1260: function validateParms() {
                   1261:     var textRegExp = /^settext_/;
                   1262:     var tailLenient = /\.lenient$/;
                   1263:     var patternRelWeight = /^\-?[\d.]+$/;
                   1264:     var patternLenientStd = /^(yes|no|default)$/;
1.597     raeburn  1265:     var ipRegExp = /^setip/;
1.549     raeburn  1266:     var ipallowRegExp = /^setipallow_/;
                   1267:     var ipdenyRegExp = /^setipdeny_/; 
1.622   ! raeburn  1268:     var graceRegExp = /^setgrace_/;
1.597     raeburn  1269:     var deeplinkRegExp = /^deeplink_/;
1.601     raeburn  1270:     var dlListScopeRegExp = /^deeplink_(state|others|listing|scope)_/; 
                   1271:     var dlLinkProtectRegExp = /^deeplink_protect_/;
                   1272:     var dlLtidRegExp = /^deeplink_ltid_/;
                   1273:     var dlLticRegExp = /^deeplink_ltic_/;
1.597     raeburn  1274:     var dlKeyRegExp = /^deeplink_key_/;
                   1275:     var dlMenusRegExp = /^deeplink_menus_/;
                   1276:     var dlCollsRegExp = /^deeplink_colls_/;
1.613     raeburn  1277:     var dlTargetRegExp = /^deeplink_target_/;
1.616     raeburn  1278:     var dlExitRegExp = /^deeplink_exit_/;
                   1279:     var dlExitTextRegExp = /^deeplink_exittext_/;
1.549     raeburn  1280:     var patternIP = /[\[\]\*\.a-zA-Z\d\-]+/;
1.616     raeburn  1281:     var numelements = document.parmform.elements.length;
                   1282:     if ((typeof(numelements) != 'undefined') && (numelements != null)) {
                   1283:         if (numelements) {
                   1284:             for (i=0; i<numelements; i++) {
1.549     raeburn  1285:                 var name=document.parmform.elements[i].name;
1.588     raeburn  1286:                 if (textRegExp.test(name)) {
1.549     raeburn  1287:                     var identifier = name.replace(textRegExp,'');
                   1288:                     if (tailLenient.test(identifier)) {
                   1289:                         if (document.parmform.elements['set_'+identifier].length) {
                   1290:                             for (var j=0; j<document.parmform.elements['set_'+identifier].length; j++) {
                   1291:                                 if (document.parmform.elements['set_'+identifier][j].checked) {
                   1292:                                     if (!(patternLenientStd.test(document.parmform.elements['set_'+identifier][j].value))) {
                   1293:                                         var relweight = document.parmform.elements[i].value;
                   1294:                                         relweight = relweight.replace(/^\s+|\s+$/g,'');
                   1295:                                         if (!patternRelWeight.test(relweight)) {
                   1296:                                             relweight = '0.0';
                   1297:                                         }
                   1298:                                         if (document.parmform.elements['set_'+identifier][j].value == 'weighted') {
                   1299:                                             document.parmform.elements['set_'+identifier][j].value = relweight;
                   1300:                                         } else {
                   1301:                                             document.parmform.elements['set_'+identifier][j].value += ','+relweight;
                   1302:                                         }
                   1303:                                     }
                   1304:                                     break;
                   1305:                                 }
                   1306:                             }
                   1307:                         }
                   1308:                     }
1.597     raeburn  1309:                 } else if (ipRegExp.test(name)) {
                   1310:                     if (ipallowRegExp.test(name)) {
                   1311:                         var identifier = name.replace(ipallowRegExp,'');
                   1312:                         var possallow = document.parmform.elements[i].value;
                   1313:                         possallow = possallow.replace(/^\s+|\s+$/g,'');
                   1314:                         if (patternIP.test(possallow)) {
                   1315:                             if (document.parmform.elements['set_'+identifier].value) {
                   1316:                                 possallow = ','+possallow;
                   1317:                             }
                   1318:                             document.parmform.elements['set_'+identifier].value += possallow;
                   1319:                         }
                   1320:                     } else if (ipdenyRegExp.test(name)) {
                   1321:                         var identifier = name.replace(ipdenyRegExp,'');
                   1322:                         var possdeny = document.parmform.elements[i].value;
                   1323:                         possdeny = possdeny.replace(/^\s+|\s+$/g,'');
                   1324:                         if (patternIP.test(possdeny)) {
                   1325:                             possdeny = '!'+possdeny;
                   1326:                             if (document.parmform.elements['set_'+identifier].value) {
                   1327:                                 possdeny = ','+possdeny;
                   1328:                             }
                   1329:                             document.parmform.elements['set_'+identifier].value += possdeny;
1.588     raeburn  1330:                         }
                   1331:                     }
                   1332:                 } else if (deeplinkRegExp.test(name)) {
1.597     raeburn  1333:                     if (dlListScopeRegExp.test(name)) {
                   1334:                         var identifier =  name.replace(dlListScopeRegExp,'');
                   1335:                         var idx = document.parmform.elements[i].selectedIndex;
                   1336:                         if (idx > 0) { 
                   1337:                             var possdeeplink = document.parmform.elements[i].options[idx].value
                   1338:                             possdeeplink = possdeeplink.replace(/^\s+|\s+$/g,'');
                   1339:                             if (document.parmform.elements['set_'+identifier].value) {
                   1340:                                 possdeeplink = ','+possdeeplink;
                   1341:                             }
                   1342:                             document.parmform.elements['set_'+identifier].value += possdeeplink;
                   1343:                         }
1.601     raeburn  1344:                     } else if (dlLinkProtectRegExp.test(name)) {
1.597     raeburn  1345:                         if (document.parmform.elements[i].checked) {
1.601     raeburn  1346:                             var identifier =  name.replace(dlLinkProtectRegExp,'');
1.597     raeburn  1347:                             var posslinkurl = document.parmform.elements[i].value;
                   1348:                             posslinkurl = posslinkurl.replace(/^\s+|\s+$/g,'');
                   1349:                             if (document.parmform.elements['set_'+identifier].value) {
                   1350:                                 posslinkurl = ','+posslinkurl;
                   1351:                             }
                   1352:                             document.parmform.elements['set_'+identifier].value += posslinkurl;
                   1353:                         }
1.601     raeburn  1354:                     } else if (dlLtidRegExp.test(name)) {
                   1355:                         var identifier = name.replace(dlLtidRegExp,'');
                   1356:                         if (isRadioSet('deeplink_protect_'+identifier,'ltid')) {
                   1357:                             var possltid = document.parmform.elements[i].value;
                   1358:                             possltid = possltid.replace(/\D+/g,'');
                   1359:                             if (possltid.length) {
1.597     raeburn  1360:                                 if (document.parmform.elements['set_'+identifier].value) {
1.601     raeburn  1361:                                     possltid = ':'+possltid;
1.597     raeburn  1362:                                 }
1.601     raeburn  1363:                                 document.parmform.elements['set_'+identifier].value += possltid;
1.597     raeburn  1364:                             } else {
                   1365:                                 document.parmform.elements['set_'+identifier].value = '';
1.601     raeburn  1366:                                 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  1367:                                 return false;  
                   1368:                             }
                   1369:                         }
1.601     raeburn  1370:                     } else if (dlLticRegExp.test(name)) {
                   1371:                         var identifier = name.replace(dlLticRegExp,'');
                   1372:                         if (isRadioSet('deeplink_protect_'+identifier,'ltic')) {
                   1373:                             var possltic = document.parmform.elements[i].value;
                   1374:                             possltic = possltic.replace(/\D+/g,'');
                   1375:                             if (possltic.length) {
                   1376:                                 if (document.parmform.elements['set_'+identifier].value) {
                   1377:                                     possltic = ':'+possltic;
                   1378:                                 }
                   1379:                                 document.parmform.elements['set_'+identifier].value += possltic;
                   1380:                             } else {
                   1381:                                 document.parmform.elements['set_'+identifier].value = '';
                   1382:                                 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.");
                   1383:                                 return false;
                   1384:                             }
                   1385:                         }
1.597     raeburn  1386:                     } else if (dlKeyRegExp.test(name)) {
                   1387:                         var identifier = name.replace(dlKeyRegExp,'');
1.601     raeburn  1388:                         if (isRadioSet('deeplink_protect_'+identifier,'key')) {
1.597     raeburn  1389:                             var posskey = document.parmform.elements[i].value;
                   1390:                             posskey = posskey.replace(/^\s+|\s+$/g,'');
                   1391:                             var origlength = posskey.length;
                   1392:                             posskey = posskey.replace(/[^a-zA-Z\d_.!@#$%^&*()+=-]/g,'');
                   1393:                             var newlength = posskey.length;
                   1394:                             if (newlength > 0) {
                   1395:                                 var change = origlength - newlength;
                   1396:                                 if (change) {
                   1397:                                     alert(change+' disallowed character(s) removed from deeplink key'); 
                   1398:                                 }
                   1399:                                 if (document.parmform.elements['set_'+identifier].value) {
                   1400:                                     posskey = ':'+posskey;
                   1401:                                 }
                   1402:                                 document.parmform.elements['set_'+identifier].value += posskey;
                   1403:                             } else {
                   1404:                                 document.parmform.elements['set_'+identifier].value = '';
                   1405:                                 if (newlength < origlength) {
                   1406:                                     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_.!@#$%^&*()+=-");
                   1407:                                 } else {
                   1408:                                     alert("A link type of 'deep with key' was selected but the key value was blank.\nPlease enter a key.");
                   1409:                                 }
                   1410:                                 return false;
                   1411:                             }
                   1412:                         }
                   1413:                     } else if (dlMenusRegExp.test(name)) {
                   1414:                         if (document.parmform.elements[i].checked) {
                   1415:                             var identifier =  name.replace(dlMenusRegExp,'');
                   1416:                             var posslinkmenu = document.parmform.elements[i].value;
                   1417:                             posslinkmenu = posslinkmenu.replace(/^\s+|\s+$/g,'');
                   1418:                             if (posslinkmenu == 'std') {
                   1419:                                 posslinkmenu = '0';
                   1420:                                 if (document.parmform.elements['set_'+identifier].value) {
                   1421:                                     posslinkmenu = ','+posslinkmenu;
                   1422:                                 }
                   1423:                                 document.parmform.elements['set_'+identifier].value += posslinkmenu;
                   1424:                             }
                   1425:                         }
                   1426:                     } else if (dlCollsRegExp.test(name)) {
                   1427:                         var identifier =  name.replace(dlCollsRegExp,'');
                   1428:                         if (isRadioSet('deeplink_menus_'+identifier,'colls')) {
                   1429:                             var posslinkmenu = document.parmform.elements[i].value;
                   1430:                             if (document.parmform.elements['set_'+identifier].value) {
                   1431:                                 posslinkmenu = ','+posslinkmenu;
                   1432:                             }
                   1433:                             document.parmform.elements['set_'+identifier].value += posslinkmenu;
                   1434:                         }
1.614     raeburn  1435:                     } else if (dlTargetRegExp.test(name)) {
                   1436:                         var identifier =  name.replace(dlTargetRegExp,'');
1.613     raeburn  1437:                         var idx = document.parmform.elements[i].selectedIndex;
                   1438:                         if (idx > 0) {
1.616     raeburn  1439:                             var linktarget = document.parmform.elements[i].options[idx].value
                   1440:                             linktarget = linktarget.replace(/^\s+|\s+$/g,'');
                   1441:                             if (document.parmform.elements['set_'+identifier].value) {
                   1442:                                 linktarget = ','+linktarget;
                   1443:                             }
                   1444:                             document.parmform.elements['set_'+identifier].value += linktarget;
                   1445:                         }
                   1446:                     } else if (dlExitRegExp.test(name)) {
                   1447:                         if (document.parmform.elements[i].checked) {
                   1448:                             var identifier =  name.replace(dlExitRegExp,'');
                   1449:                             var posslinkexit = document.parmform.elements[i].value;
                   1450:                             posslinkexit = posslinkexit.replace(/^\s+|\s+$/g,'');
1.613     raeburn  1451:                             if (document.parmform.elements['set_'+identifier].value) {
1.616     raeburn  1452:                                 posslinkexit = ','+posslinkexit;
                   1453:                             }
                   1454:                             document.parmform.elements['set_'+identifier].value += posslinkexit;
                   1455:                         }
                   1456:                     } else if (dlExitTextRegExp.test(name)) {
                   1457:                         var identifier = name.replace(dlExitTextRegExp,'');
                   1458:                         if ((isRadioSet('deeplink_exit_'+identifier,'yes')) ||
                   1459:                             (isRadioSet('deeplink_exit_'+identifier,'url'))) {
                   1460:                             var posstext = document.parmform.elements[i].value;
                   1461:                             posstext = posstext.replace(/^\s+|\s+$/g,'');
                   1462:                             var origlength = posstext.length;
                   1463:                             posstext = posstext.replace(/[:;'",]/g,'');
                   1464:                             var newlength = posstext.length;
                   1465:                             if (newlength > 0) {
                   1466:                                 var change = origlength - newlength;
                   1467:                                 if (change) {
                   1468:                                     alert(change+' disallowed character(s) removed from Exit Button text');
                   1469:                                 }
                   1470:                                 if (posstext !== 'Exit Tool') {
                   1471:                                     posstext = ':'+posstext;
                   1472:                                     document.parmform.elements['set_'+identifier].value += posstext;
                   1473:                                 }
                   1474:                             } else {
                   1475:                                 document.parmform.elements['set_'+identifier].value = '';
                   1476:                                 if (newlength < origlength) {
                   1477:                                     alert("An exit link type of 'In use' was selected but the button text value was blank, after removing disallowed characters.\nDisallowed characters are ,\":;'");
                   1478:                                 } else {
                   1479:                                     alert("An exit link type of 'In use' was selected but the button text value was blank.\nPlease enter the text to use.");
                   1480:                                 }
                   1481:                                 return false;
1.613     raeburn  1482:                             }
                   1483:                         }
1.549     raeburn  1484:                     }
1.622   ! raeburn  1485:                 } else if (graceRegExp.test(name)) {
        !          1486:                     var identifier = name.replace(graceRegExp,'');
        !          1487:                     var divElem = document.parmform.elements[i].closest('div'); 
        !          1488:                     var timeSels = divElem.getElementsByTagName("select");
        !          1489:                     var total = 0;
        !          1490:                     if (timeSels.length) {
        !          1491:                          for (var j=0; j<timeSels.length; j++) {
        !          1492:                             var sname = timeSels[j].getAttribute('name');
        !          1493:                             var poss = parseInt(timeSels[j].options[timeSels[j].selectedIndex].value);
        !          1494:                             if (sname == 'days_'+identifier) {
        !          1495:                                 if ((poss > 0) && (poss <= 31)) {
        !          1496:                                     total += (poss * 86400); 
        !          1497:                                 }
        !          1498:                             } else if (sname == 'hours_'+identifier) {
        !          1499:                                 if ((poss > 0) && (poss < 24)) {
        !          1500:                                     total += (poss * 3600);
        !          1501:                                 }
        !          1502:                             } else if (sname == 'minutes_'+identifier) {
        !          1503:                                 if ((poss > 0) && (poss < 60)) {
        !          1504:                                     total += (poss * 60);
        !          1505:                                 }
        !          1506:                             } else if (sname == 'seconds_'+identifier) {
        !          1507:                                 if ((poss > 0) && (poss < 60)) {
        !          1508:                                     total += poss;
        !          1509:                                 }
        !          1510:                             }
        !          1511:                         }
        !          1512:                     }
        !          1513:                     var inputElems = divElem.getElementsByTagName("input");
        !          1514:                     var frac = '';
        !          1515:                     var grad = '';
        !          1516:                     if (inputElems.length) {
        !          1517:                         for (var j=0; j<inputElems.length; j++) {
        !          1518:                             var iname = inputElems[j].getAttribute('name');
        !          1519:                             if (iname == 'frac_'+identifier) {
        !          1520:                                 var ival = inputElems[j].value;
        !          1521:                                 ival.trim();
        !          1522:                                 var poss = parseFloat(ival);
        !          1523:                                 if ((typeof poss === 'number') && (!isNaN(poss))) {
        !          1524:                                     if ((poss => 0) && (poss <= 1)) {
        !          1525:                                         frac = poss;
        !          1526:                                     }
        !          1527:                                 }
        !          1528:                             } else if (iname == 'grad_'+identifier) {
        !          1529:                                 if (inputElems[j].checked) {
        !          1530:                                     grad = 1;
        !          1531:                                 } else {
        !          1532:                                     grad = 0;
        !          1533:                                 }
        !          1534:                             }
        !          1535:                         }
        !          1536:                     }
        !          1537:                     document.parmform.elements[i].value = total+':'+frac+':'+grad;
        !          1538:                     if (document.parmform.elements['set_'+identifier].value) {
        !          1539:                         document.parmform.elements['set_'+identifier].value += ',';
        !          1540:                     }
        !          1541:                     document.parmform.elements['set_'+identifier].value += document.parmform.elements[i].value;
1.549     raeburn  1542:                 }
                   1543:             }
                   1544:         }
                   1545:     }
                   1546:     return true;
                   1547: }
                   1548: 
1.597     raeburn  1549: function isRadioSet(name,expected) {
                   1550:     var menuitems = document.getElementsByName(name);
                   1551:     var radioLength = menuitems.length;
                   1552:     result = false;
                   1553:     if (radioLength  > 1) {
                   1554:         for (var j=0; j<radioLength; j++) {
                   1555:             if (menuitems[j].checked) {
                   1556:                 if (menuitems[j].value == expected) {
                   1557:                     result = true;
                   1558:                     break;
                   1559:                 }
                   1560:             }
                   1561:         }
                   1562:     }
                   1563:     return result;
                   1564: }
                   1565: 
1.549     raeburn  1566: ENDSCRIPT
                   1567: }
                   1568: 
1.561     damieng  1569: # Javascript initialization, for overview mode
1.549     raeburn  1570: sub ipacc_boxes_js  {
                   1571:     my $remove = &mt('Remove');
                   1572:     return <<"END";
                   1573: \$(document).ready(function() {
                   1574:     var wrapper         = \$(".LC_string_ipacc_wrap");
                   1575:     var add_button      = \$(".LC_add_ipacc_button");
                   1576:     var ipaccRegExp     = /^LC_string_ipacc_/;
                   1577: 
                   1578:     \$(add_button).click(function(e){
                   1579:         e.preventDefault();
                   1580:         var identifier = \$(this).closest("div").attr("id");
                   1581:         identifier = identifier.replace(ipaccRegExp,'');
1.551     raeburn  1582:         \$(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  1583:     });
                   1584: 
                   1585:     \$(wrapper).delegate(".LC_remove_ipacc","click", function(e){
                   1586:         e.preventDefault(); \$(this).closest("div").remove();
                   1587:     })
                   1588: });
                   1589: 
                   1590: 
                   1591: END
                   1592: }
                   1593: 
1.622   ! raeburn  1594: sub grace_js {
        !          1595:     my %lt = &grace_titles();
        !          1596:     &js_escape(\%lt);
        !          1597:     my $overdue = '<fieldset class="LC_grace"><legend>'.$lt{'sinc'}.'</legend>';
        !          1598:     foreach my $which (['days', 86400, 31],
        !          1599:                        ['hours', 3600, 23],
        !          1600:                        ['minutes', 60, 59],
        !          1601:                        ['seconds',  1, 59]) {
        !          1602:         my ($name, $factor, $max) = @{ $which };
        !          1603:         my %select = ((map {$_ => $_} (0..$max)),
        !          1604:                       'select_form_order' => [0..$max]);
        !          1605:         my $selector = &Apache::loncommon::select_form('',$name."_'+identifier+'",
        !          1606:                                                        \%select);
        !          1607:         $selector =~ s/([\r\n\f]+)//g;
        !          1608:         $overdue .= $selector.'&nbsp;'.$lt{$name}.('&nbsp;'x2).' ';
        !          1609:     }
        !          1610:     $overdue .= '</fieldset>';
        !          1611:     return <<"END";
        !          1612: \$(document).ready(function() {
        !          1613:     var wrapper         = \$(".LC_string_grace_wrap");
        !          1614:     var add_button      = \$(".LC_add_grace_button");
        !          1615:     var graceRegExp     = /^LC_string_grace_/;
        !          1616: 
        !          1617:     \$(add_button).click(function(e){
        !          1618:         e.preventDefault();
        !          1619:         var identifier = \$(this).closest("div").attr("id");
        !          1620:         identifier = identifier.replace(graceRegExp,'');
        !          1621:         \$(this).closest('div').find('.LC_string_grace_inner').append('<div><input type="hidden" name="setgrace_'+identifier+'" value="" />$overdue<fieldset class="LC_grace"><legend>$lt{scor}</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>');
        !          1622:     });
        !          1623: 
        !          1624:     \$(wrapper).delegate(".LC_remove_grace","click", function(e){
        !          1625:         e.preventDefault(); \$(this).closest("div").remove();
        !          1626:     })
        !          1627: });
        !          1628: 
        !          1629: 
        !          1630: END
        !          1631: }
        !          1632: 
1.561     damieng  1633: # Javascript function toggleSecret, for overview mode.
1.558     raeburn  1634: sub done_proctor_js {
1.611     raeburn  1635:     my $defaultdone = &mt('Done');
                   1636:     &js_escape(\$defaultdone);
1.558     raeburn  1637:     return <<"END";
                   1638: function toggleSecret(form,radio,key) {
                   1639:     var radios = form[radio+key];
                   1640:     if (radios.length) {
                   1641:         for (var i=0; i<radios.length; i++) {
                   1642:             if (radios[i].checked) {
                   1643:                 if (radios[i].value == '_done_proctor') {
                   1644:                     if (document.getElementById('done_'+key+'_proctorkey')) {
                   1645:                         document.getElementById('done_'+key+'_proctorkey').type='text';
                   1646:                     }
                   1647:                 } else {
                   1648:                     if (document.getElementById('done_'+key+'_proctorkey')) {
                   1649:                         document.getElementById('done_'+key+'_proctorkey').type='hidden';
                   1650:                         document.getElementById('done_'+key+'_proctorkey').value='';
                   1651:                     }
                   1652:                 }
1.611     raeburn  1653:                 if (document.getElementById('done_'+key+'_buttontext')) {
                   1654:                     if (radios[i].value == '') {
                   1655:                         document.getElementById('done_'+key+'_buttontext').value = '';
                   1656:                     } else {
                   1657:                         if (document.getElementById('done_'+key+'_buttontext').value == '') {
                   1658:                             document.getElementById('done_'+key+'_buttontext').value = '$defaultdone';
                   1659:                         }
                   1660:                     }
                   1661:                 }
1.558     raeburn  1662:             }
                   1663:         }
                   1664:     }
                   1665: }
                   1666: END
                   1667: 
                   1668: }
                   1669: 
1.588     raeburn  1670: # Javascript function toggle
                   1671: sub deeplink_js {
                   1672:     return <<"END";
                   1673: function toggleDeepLink(form,item,key) {
                   1674:     var radios = form['deeplink_'+item+'_'+key];
                   1675:     if (radios.length) {
                   1676:         var keybox;
                   1677:         if (document.getElementById('deeplink_key_'+item+'_'+key)) {
                   1678:             keybox = document.getElementById('deeplink_key_'+item+'_'+key);
                   1679:         }
1.601     raeburn  1680:         var divoptions = new Array();
                   1681:         if (item == 'protect') {
                   1682:             divoptions = ['ltic','ltid'];
1.597     raeburn  1683:         } else {
                   1684:             if (item == 'menus') {
1.601     raeburn  1685:                 divoptions = ['colls'];
1.597     raeburn  1686:             }
                   1687:         }
1.601     raeburn  1688:         var seldivs = new Array();
                   1689:         if ((item == 'protect') || (item == 'menus')) {
                   1690:             for (var i=0; i<divoptions.length; i++) {
                   1691:                 if (document.getElementById('deeplinkdiv_'+divoptions[i]+'_'+item+'_'+key)) {
                   1692:                     seldivs[i] = document.getElementById('deeplinkdiv_'+divoptions[i]+'_'+item+'_'+key);
                   1693:                 } else {
                   1694:                     seldivs[i] = '';
                   1695:                 }
                   1696:             }
1.588     raeburn  1697:         }
                   1698:         for (var i=0; i<radios.length; i++) {
                   1699:             if (radios[i].checked) {
1.601     raeburn  1700:                 if ((item == 'protect') || (item == 'menus')) {
                   1701:                     for (var j=0; j<seldivs.length; j++) {
                   1702:                         if (radios[i].value == divoptions[j]) {
                   1703:                             if (seldivs[j] != '') {
                   1704:                                 seldivs[j].style.display = 'inline-block';
                   1705:                             }
                   1706:                             if (item == 'protect') {
                   1707:                                 keybox.type = 'hidden';
                   1708:                                 keybox.value = '';
                   1709:                             }
                   1710:                         } else {
                   1711:                             if (seldivs[j] != '') {
                   1712:                                 seldivs[j].style.display = 'none';
                   1713:                                 form['deeplink_'+divoptions[j]+'_'+key].selectedIndex = 0;
                   1714:                             }
                   1715:                         }
1.597     raeburn  1716:                     }
1.601     raeburn  1717:                     if (item == 'protect') {
1.597     raeburn  1718:                         if (radios[i].value == 'key') {
                   1719:                             keybox.type = 'text';
                   1720:                         } else {
                   1721:                             keybox.type = 'hidden';
                   1722:                         }
1.588     raeburn  1723:                     }
1.616     raeburn  1724:                 } else if (item == 'exit') {
                   1725:                     if (document.getElementById('deeplinkdiv_'+item+'_'+key)) {
                   1726:                         if (radios[i].value == 'no') {
                   1727:                             document.getElementById('deeplinkdiv_'+item+'_'+key).style.display = 'none';          
                   1728:                             if (document.getElementById('deeplink_exittext_'+key)) {
                   1729:                                 if (document.getElementById('deeplink_exittext_'+key).value != '') {
                   1730:                                     document.getElementById('deeplink_exittext_'+key).value = '';    
                   1731:                                 }
                   1732:                             }
                   1733:                         } else {
                   1734:                             document.getElementById('deeplinkdiv_'+item+'_'+key).style.display = 'inline-block';
                   1735:                             if (document.getElementById('deeplink_exittext_'+key)) {
                   1736:                                 if (document.getElementById('deeplink_exittext_'+key).value == '') {
                   1737:                                     document.getElementById('deeplink_exittext_'+key).value = 'Exit Tool';
                   1738:                                 }
                   1739:                             }
                   1740:                         }
                   1741:                     }
1.588     raeburn  1742:                 }
                   1743:             }
                   1744:         }
                   1745:     }
                   1746: }
                   1747: END
                   1748: 
                   1749: }
                   1750: 
1.561     damieng  1751: # Prints HTML page start for table mode.
                   1752: # @param {Apache2::RequestRec} $r - the Apache request
                   1753: # @param {string} $psymb - resource symb
                   1754: # @param {string} $crstype - course type (Community / Course / Placement Test)
1.280     albertel 1755: sub startpage {
1.531     raeburn  1756:     my ($r,$psymb,$crstype) = @_;
1.281     albertel 1757: 
1.515     raeburn  1758:     my %loaditems = (
                   1759:                       'onload'   => "group_or_section('cgroup')",
                   1760:                     );
                   1761:     if (!$psymb) {
1.523     raeburn  1762:         $loaditems{'onload'} = "showHide_courseContent(); group_or_section('cgroup'); resize_scrollbox('mapmenuscroll','1','1');";
1.515     raeburn  1763:     }
1.280     albertel 1764: 
1.560     damieng  1765:     if ((($env{'form.command'} eq 'set') && ($env{'form.url'}) &&
                   1766:             (!$env{'form.dis'})) || ($env{'form.symb'})) {
                   1767:         &Apache::lonhtmlcommon::add_breadcrumb({help=>'Problem_Parameters',
                   1768:             text=>"Problem Parameters"});
1.414     droeschl 1769:     } else {
1.560     damieng  1770:         &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=settable',
                   1771:             text=>"Table Mode",
                   1772:             help => 'Course_Setting_Parameters'});
1.414     droeschl 1773:     }
1.523     raeburn  1774:     my $js = &page_js().'
                   1775: <script type="text/javascript">
                   1776: // <![CDATA[
                   1777: '.
                   1778:             &Apache::lonhtmlcommon::resize_scrollbox_js('params').'
                   1779: // ]]>
                   1780: </script>
                   1781: ';
1.446     bisitz   1782:     my $start_page =
1.523     raeburn  1783:         &Apache::loncommon::start_page('Set/Modify Course Parameters',$js,
                   1784:                                        {'add_entries' => \%loaditems,});
1.446     bisitz   1785:     my $breadcrumbs =
1.473     amueller 1786:     &Apache::lonhtmlcommon::breadcrumbs('Table Mode Parameter Setting','Table_Mode');
1.506     www      1787:     my $escfilter=&Apache::lonhtmlcommon::entity_encode($env{'form.filter'});
                   1788:     my $escpart=&Apache::lonhtmlcommon::entity_encode($env{'form.part'});
1.507     www      1789:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  1790:     &startSettingsScreen($r,'parmset',$crstype);
1.280     albertel 1791:     $r->print(<<ENDHEAD);
1.193     albertel 1792: <form method="post" action="/adm/parmset?action=settable" name="parmform">
1.419     bisitz   1793: <input type="hidden" value="" name="pres_value" />
                   1794: <input type="hidden" value="" name="pres_type" />
                   1795: <input type="hidden" value="" name="pres_marker" />
                   1796: <input type="hidden" value="1" name="prevvisit" />
1.506     www      1797: <input type="hidden" value="$escfilter" name="filter" />
                   1798: <input type="hidden" value="$escpart" name="part" />
1.44      albertel 1799: ENDHEAD
                   1800: }
                   1801: 
1.209     www      1802: 
1.561     damieng  1803: # Prints a row for table mode (except for the tr start).
                   1804: # Every time a hash reference is passed, a single entry is used, so print_row
                   1805: # could just use these values, but why make it simple when it can be complicated ?
                   1806: #
                   1807: # @param {Apache2::RequestRec} $r - the Apache request
                   1808: # @param {string} $which - parameter key ('parameter_'.part.'_'.name)
                   1809: # @param {hash reference} $part - parameter key -> parameter part (can be problem part.'_'.response id for response parameters)
                   1810: # @param {hash reference} $name - parameter key -> parameter name
1.566     damieng  1811: # @param {hash reference} $symbp - map pc or resource/map id -> map src.'___(all)' or resource symb
1.561     damieng  1812: # @param {string} $rid - resource id
                   1813: # @param {hash reference} $default - parameter key -> resource parameter default value
                   1814: # @param {hash reference} $defaulttype - parameter key -> resource parameter default type
                   1815: # @param {hash reference} $display - parameter key -> full title for the parameter
                   1816: # @param {string} $defbgone - user level and other levels background color
                   1817: # @param {string} $defbgtwo - section level background color, also used for part number
                   1818: # @param {string} $defbgthree - group level background color
                   1819: # @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general')
                   1820: # @param {string} $uname - user name
                   1821: # @param {string} $udom - user domain
                   1822: # @param {string} $csec - section name
                   1823: # @param {string} $cgroup - group name
                   1824: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   1825: # @param {boolean} $noeditgrp - true if no edit is allowed for group level parameters
1.582     raeburn  1826: # @param {boolean} $readonly - true if no editing allowed.
                   1827: # @param {array reference} - $recurseup - list of maps containing current one, ending at top-level.
                   1828: # @param {hash reference} - $maptitles - - hash map id or src -> map title 
                   1829: # @param {hash reference} - $allmaps_inverted - hash map src -> map pc
                   1830: # @param {scalar reference} - $reclinks - number of "parameter in effect" cells with link to map where recursive param was set 
1.44      albertel 1831: sub print_row {
1.201     www      1832:     my ($r,$which,$part,$name,$symbp,$rid,$default,$defaulttype,$display,$defbgone,
1.568     raeburn  1833:     $defbgtwo,$defbgthree,$parmlev,$uname,$udom,$csec,$cgroup,$usersgroups,$noeditgrp,
1.582     raeburn  1834:     $readonly,$recurseup,$maptitles,$allmaps_inverted,$reclinks)=@_;
1.275     raeburn  1835:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   1836:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   1837:     my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
1.582     raeburn  1838:     my $numlinks = 0;
1.553     raeburn  1839: 
1.560     damieng  1840:     # get the values for the parameter in cascading order
                   1841:     # empty levels will remain empty
1.44      albertel 1842:     my ($result,@outpar)=&parmval($$part{$which}.'.'.$$name{$which},
1.473     amueller 1843:       $rid,$$default{$which},$uname,$udom,$csec,$cgroup,$courseopt);
1.560     damieng  1844:     # get the type for the parameters
                   1845:     # problem: these may not be set for all levels
1.66      www      1846:     my ($typeresult,@typeoutpar)=&parmval($$part{$which}.'.'.
1.275     raeburn  1847:                                           $$name{$which}.'.type',$rid,
1.473     amueller 1848:          $$defaulttype{$which},$uname,$udom,$csec,$cgroup,$courseopt);
1.560     damieng  1849:     # cascade down manually
1.182     albertel 1850:     my $cascadetype=$$defaulttype{$which};
1.556     raeburn  1851:     for (my $i=18;$i>0;$i--) {
1.560     damieng  1852:         if ($typeoutpar[$i]) {
1.66      www      1853:             $cascadetype=$typeoutpar[$i];
1.560     damieng  1854:         } else {
1.66      www      1855:             $typeoutpar[$i]=$cascadetype;
                   1856:         }
                   1857:     }
1.57      albertel 1858:     my $parm=$$display{$which};
                   1859: 
1.203     www      1860:     if ($parmlev eq 'full') {
1.419     bisitz   1861:         $r->print('<td style="background-color:'.$defbgtwo.';" align="center">'
1.506     www      1862:                   .($$part{$which} eq '0'?'0 ('.&mt('default').')':$$part{$which}).'</td>');
1.433     raeburn  1863:     } else {
1.57      albertel 1864:         $parm=~s|\[.*\]\s||g;
                   1865:     }
1.231     www      1866:     my $automatic=&rulescache(($which=~/\_([^\_]+)$/)[0].'_triggers');
                   1867:     if ($automatic) {
1.560     damieng  1868:         $parm.='<span class="LC_warning"><br />'.&mt('Automatically sets').' '.join(', ',split(/\:/,$automatic)).'</span>';
1.231     www      1869:     }
1.619     raeburn  1870:     my $advice;
                   1871:     if ((ref($name) eq 'HASH') && ($name->{$which} eq 'mapalias') &&
                   1872:         (ref($symbp) eq 'HASH') && ($parmlev eq 'full')) {
                   1873:         if ($symbp->{$rid} =~ m{^uploaded/}) {
                   1874:             if ($result == 14) {
                   1875:                 $advice = &mt('Use Course Editor to modify this.');
                   1876:             } else {
                   1877:                 $advice = &mt('Use Course Editor to set this.');
                   1878:             }
                   1879:         } else {
                   1880:             if ($result == 14) {
                   1881:                 $advice = &mt('Use Resource Assembly Tool to modify this.');
                   1882:             } else {
                   1883:                 $advice = &mt('Use Resource Assembly Tool to set this.');
                   1884:             }
                   1885:         }
                   1886:         $parm .= '<br /><span class="LC_fontsize_small LC_cusr_emph">'.$advice.'</span>';
                   1887:     }
1.427     bisitz   1888:     $r->print('<td>'.$parm.'</td>');
1.446     bisitz   1889: 
1.44      albertel 1890:     my $thismarker=$which;
                   1891:     $thismarker=~s/^parameter\_//;
                   1892:     my $mprefix=$rid.'&'.$thismarker.'&';
1.582     raeburn  1893:     my ($parmname)=($thismarker=~/\_([^\_]+)$/);
                   1894:     my ($othergrp,$grp_parm,$controlgrp,$effective_parm,$effparm_rec,$effparm_level,
1.588     raeburn  1895:         $eff_groupparm,$recurse_check,$recursinfo,$extra);
1.582     raeburn  1896:     if ((ref($recurseup) eq 'ARRAY') && (@{$recurseup} > 0)) {
                   1897:         if ($result eq '') {
                   1898:             $recurse_check = 1;
                   1899:         } elsif (($uname ne '') && ($result > 3)) {
                   1900:             $recurse_check = 1;
                   1901:         } elsif (($cgroup ne '') && ($result > 7)) {
                   1902:             $recurse_check = 1;
                   1903:         } elsif (($csec ne '') && ($result > 11)) {
                   1904:             $recurse_check = 1;
                   1905:         } elsif ($result > 17) {
                   1906:             $recurse_check = 1;
                   1907:         }
                   1908:         if ($recurse_check) {
                   1909:             my $what = $$part{$which}.'.'.$$name{$which};
                   1910:             my $prefix;
                   1911:             if (($uname ne '') && ($udom ne '')) {
                   1912:                 my $useropt = &Apache::lonnet::get_userresdata($uname,$udom);
                   1913:                 $prefix = $env{'request.course.id'};
                   1914:                 $recursinfo = &get_recursive($recurseup,$useropt,$what,$prefix);
                   1915:                 if (ref($recursinfo) eq 'ARRAY') {
                   1916:                     $effparm_rec = 1;
                   1917:                     $effparm_level = &mt('user: [_1]',$uname);
                   1918:                 }
                   1919:             }
                   1920:             if (($cgroup ne '') && (!$effparm_rec)) {
                   1921:                 $prefix = $env{'request.course.id'}.'.['.$cgroup.']';
                   1922:                 $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix);
                   1923:                 if (ref($recursinfo) eq 'ARRAY') {
                   1924:                     $effparm_rec = 1;
                   1925:                     $effparm_level = &mt('group: [_1]',$cgroup);
                   1926:                 }
                   1927:             }
                   1928:             if (($csec ne '') && (!$effparm_rec)) {
                   1929:                 $prefix = $env{'request.course.id'}.'.['.$csec.']';
                   1930:                 $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix);
                   1931:                 if (ref($recursinfo) eq 'ARRAY') {
                   1932:                     $effparm_rec = 1;
                   1933:                     $effparm_level = &mt('section: [_1]',$csec);
                   1934:                 }
                   1935:             }
                   1936:             if (!$effparm_rec) {
                   1937:                 $prefix = $env{'request.course.id'};
                   1938:                 $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix); 
                   1939:                 if (ref($recursinfo) eq 'ARRAY') {
                   1940:                     $effparm_rec = 1;
                   1941:                 }
                   1942:             }
                   1943:         }
                   1944:     }
                   1945:     if ((!$effparm_rec) && ($result == 17 || $result == 11 || $result == 7 || $result == 3)) {
                   1946:         $effparm_rec = 1;
                   1947:     }
                   1948:     if ((!$effparm_rec) && 
                   1949:         (($$name{$which} eq 'encrypturl') || ($$name{$which} eq 'hiddenresource')) && 
                   1950:         ($result == 16 || $result == 10 || $result == 6 || $result == 2)) {
1.578     raeburn  1951:         $effparm_rec = 1;
                   1952:     }
1.588     raeburn  1953:     if ($parmname eq 'deeplink') {
1.601     raeburn  1954:         my ($domltistr,$crsltistr);
1.588     raeburn  1955:         my %lti =
                   1956:             &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'},
1.604     raeburn  1957:                                             'linkprot');
1.601     raeburn  1958:         if (keys(%lti)) {
                   1959:             foreach my $item (sort { $a <=> $b }  (keys(%lti))) {
1.604     raeburn  1960:                 if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) {
                   1961:                     $domltistr .= $item.':'.&escape(&escape($lti{$item}{'name'})).',';
1.588     raeburn  1962:                 }
                   1963:             }
1.601     raeburn  1964:             $domltistr =~ s/,$//;
                   1965:             if ($domltistr) {
                   1966:                 $extra = 'ltid_'.$domltistr;
                   1967:             }
1.588     raeburn  1968:         }
1.620     raeburn  1969:         my %courselti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider');
1.601     raeburn  1970:         if (keys(%courselti)) {
                   1971:             foreach my $item (sort { $a <=> $b } keys(%courselti)) {
                   1972:                 if (($item =~ /^\d+$/) && (ref($courselti{$item}) eq 'HASH')) {
                   1973:                     $crsltistr .= $item.':'.&escape(&escape($courselti{$item}{'name'})).',';
                   1974:                 }
                   1975:             }
                   1976:             $crsltistr =~ s/,$//;
                   1977:             if ($crsltistr) {
                   1978:                 if ($extra) {
                   1979:                     $extra .= '&';
                   1980:                 }
                   1981:                 $extra .= 'ltic_'.$crsltistr;
1.588     raeburn  1982:             }
                   1983:         }
1.597     raeburn  1984:         if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) {
                   1985:             my @colls;
                   1986:             foreach my $item (split(/;/,$env{'course.'.$env{'request.course.id'}.'.menucollections'})) {
                   1987:                 my ($num,$value) = split(/\%/,$item);
                   1988:                 if ($num =~ /^\d+$/) {
                   1989:                     push(@colls,$num);
                   1990:                 }
                   1991:             }
                   1992:             if (@colls) {
                   1993:                 if ($extra) {
                   1994:                     $extra .= '&';
                   1995:                 }
                   1996:                 $extra .= 'menus_'.join(',',@colls);
                   1997:             }
                   1998:         }
1.588     raeburn  1999:     }
1.57      albertel 2000:     if ($parmlev eq 'general') {
                   2001:         if ($uname) {
1.588     raeburn  2002:             &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.269     raeburn  2003:         } elsif ($cgroup) {
1.588     raeburn  2004:             &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra);
1.57      albertel 2005:         } elsif ($csec) {
1.588     raeburn  2006:             &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.57      albertel 2007:         } else {
1.588     raeburn  2008:             &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.57      albertel 2009:         }
                   2010:     } elsif ($parmlev eq 'map') {
                   2011:         if ($uname) {
1.588     raeburn  2012:             &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
1.269     raeburn  2013:         } elsif ($cgroup) {
1.588     raeburn  2014:             &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra);
1.57      albertel 2015:         } elsif ($csec) {
1.588     raeburn  2016:             &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
1.57      albertel 2017:         } else {
1.588     raeburn  2018:             &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
1.57      albertel 2019:         }
                   2020:     } else {
1.275     raeburn  2021:         if ($uname) {
                   2022:             if (@{$usersgroups} > 1) {
1.582     raeburn  2023:                 (my $coursereply,$othergrp,$grp_parm,$controlgrp,my $grp_is_rec) =
1.580     raeburn  2024:                     &check_other_groups($$part{$which}.'.'.$$name{$which},
1.275     raeburn  2025:                        $rid,$cgroup,$defbgone,$usersgroups,$result,$courseopt);
1.582     raeburn  2026:                 if (($coursereply) && ($result > 4)) {
1.275     raeburn  2027:                     if (defined($controlgrp)) {
                   2028:                         if ($cgroup ne $controlgrp) {
1.582     raeburn  2029:                             $eff_groupparm = $grp_parm;
                   2030:                             undef($result);
                   2031:                             undef($effparm_rec);
                   2032:                             if ($grp_is_rec) {
                   2033:                                  $effparm_rec = 1;
                   2034:                             }
1.275     raeburn  2035:                         }
                   2036:                     }
                   2037:                 }
                   2038:             }
                   2039:         }
1.57      albertel 2040: 
1.588     raeburn  2041:         &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2042:         &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
                   2043:         &print_td($r,15,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2044:         &print_td($r,14,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2045:         &print_td($r,13,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.548     raeburn  2046: 
                   2047:         if ($csec) {
1.588     raeburn  2048:             &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2049:             &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
                   2050:             &print_td($r,9,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.548     raeburn  2051:         }
1.269     raeburn  2052: 
                   2053:         if ($cgroup) {
1.588     raeburn  2054:             &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra);
                   2055:             &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra);
                   2056:             &print_td($r,5,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp.$readonly,'',$extra);
1.269     raeburn  2057:         }
1.446     bisitz   2058: 
1.548     raeburn  2059:         if ($uname) {
1.275     raeburn  2060:             if ($othergrp) {
                   2061:                 $r->print($othergrp);
                   2062:             }
1.588     raeburn  2063:             &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
                   2064:             &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra);
                   2065:             &print_td($r,1,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra);
1.548     raeburn  2066:         }
1.57      albertel 2067:     } # end of $parmlev if/else
1.582     raeburn  2068:     if (ref($recursinfo) eq 'ARRAY') {
                   2069:         my $rectitle = &mt('recursive');
                   2070:         if ((ref($maptitles) eq 'HASH') && (exists($maptitles->{$recursinfo->[2]}))) {
                   2071:             if ((ref($allmaps_inverted) eq 'HASH') && (exists($allmaps_inverted->{$recursinfo->[2]}))) {
                   2072:                 $rectitle = &mt('set in: [_1]','"'.
                   2073:                                 '<a href="javascript:pjumprec('."'".$allmaps_inverted->{$recursinfo->[2]}."',".
                   2074:                                                               "'$parmname','$$part{$which}'".');">'.
                   2075:                                 $maptitles->{$recursinfo->[2]}.'</a>"');
                   2076:               
                   2077:                 $numlinks ++;
                   2078:             }
                   2079:         }
                   2080:         my ($parmname)=($thismarker=~/\_([^\_]+)$/);
1.593     raeburn  2081:         $effective_parm = &valout($recursinfo->[0],$recursinfo->[1]);
1.582     raeburn  2082:         $r->print('<td style="background-color:#CCCCFF;" align="center">'.$effective_parm.
                   2083:                   '<br /><span class="LC_parm_recursive">'.$rectitle.'&nbsp;'.
                   2084:                   $effparm_level.'</span></td>');
                   2085:     } else {
                   2086:         if ($result) {
1.593     raeburn  2087:             $effective_parm = &valout($outpar[$result],$typeoutpar[$result]);
1.582     raeburn  2088:         }
                   2089:         if ($eff_groupparm) {
                   2090:             $effective_parm = $eff_groupparm;
                   2091:         }
                   2092:         $r->print('<td style="background-color:#CCCCFF;" align="center">'.$effective_parm.
                   2093:                   ($effparm_rec?'<br /><span class="LC_parm_recursive">'.&mt('recursive').
                   2094:                                 '</span>':'').'</td>');
                   2095:     }
1.203     www      2096:     if ($parmlev eq 'full') {
1.136     albertel 2097:         my $sessionval=&Apache::lonnet::EXT('resource.'.$$part{$which}.
1.201     www      2098:                                         '.'.$$name{$which},$$symbp{$rid});
1.136     albertel 2099:         my $sessionvaltype=$typeoutpar[$result];
1.560     damieng  2100:         if (!defined($sessionvaltype)) {
                   2101:             $sessionvaltype=$$defaulttype{$which};
                   2102:         }
1.419     bisitz   2103:         $r->print('<td style="background-color:#999999;" align="center"><font color="#FFFFFF">'.
1.593     raeburn  2104:                   &valout($sessionval,$sessionvaltype).'&nbsp;'.
1.57      albertel 2105:                   '</font></td>');
1.136     albertel 2106:     }
1.44      albertel 2107:     $r->print('</tr>');
1.57      albertel 2108:     $r->print("\n");
1.582     raeburn  2109:     if (($numlinks) && (ref($reclinks))) {
                   2110:         $$reclinks = $numlinks;
                   2111:     }
1.44      albertel 2112: }
1.59      matthew  2113: 
1.561     damieng  2114: # Prints a cell for table mode.
                   2115: #
                   2116: # FIXME: some of these parameter names are uninspired ($which and $value)
                   2117: # Also, it would make more sense to pass the display for this cell rather
                   2118: # than the full display hash and the key to use.
                   2119: #
                   2120: # @param {Apache2::RequestRec} $r - the Apache request
                   2121: # @param {integer} $which - level
                   2122: # @param {string} $defbg - cell background color
                   2123: # @param {integer} $result - the most specific level that is defined for that parameter
                   2124: # @param {array reference} $outpar - array level -> parameter value (when defined)
                   2125: # @param {string} $mprefix - resource id.'&'.part.'_'.parameter name.'&'
                   2126: # @param {string} $value - parameter key ('parameter_'.part.'_'.name)
                   2127: # @param {array reference} $typeoutpar - array level -> parameter type (when defined)
                   2128: # @param {hash reference} $display - parameter key -> full title for the parameter
                   2129: # @param {boolean} $noeditgrp - true if no edit is allowed for group level parameters
1.568     raeburn  2130: # @param {boolean} $readonly -true if editing not allowed.
1.588     raeburn  2131: # @param {boolean} $ismaplevel - true if level is for a map.
1.597     raeburn  2132: # @param {string} $extra - extra information to pass to plink.
1.44      albertel 2133: sub print_td {
1.578     raeburn  2134:     my ($r,$which,$defbg,$result,$outpar,$mprefix,$value,$typeoutpar,$display,
1.588     raeburn  2135:         $noeditgrp,$readonly,$ismaplevel,$extra)=@_;
1.578     raeburn  2136:     my ($ineffect,$recursive,$currval,$currtype,$currlevel);
                   2137:     $ineffect = 0;
                   2138:     $currval = $$outpar[$which];
                   2139:     $currtype = $$typeoutpar[$which];
                   2140:     $currlevel = $which;
                   2141:     if (($result) && ($result == $which)) {
                   2142:         $ineffect = 1;
                   2143:     } 
                   2144:     if ($ismaplevel) {
                   2145:         if ($mprefix =~ /(hiddenresource|encrypturl)\&/) {
                   2146:             if (($result) && ($result == $which)) {
                   2147:                 $recursive = 1;
                   2148:             }
                   2149:         } elsif ($$outpar[$which+1] ne '') {
                   2150:             $recursive = 1;
                   2151:             $currlevel = $which+1;
                   2152:             $currval = $$outpar[$currlevel];
                   2153:             $currtype = $$typeoutpar[$currlevel];
                   2154:             if (($result) && ($result == $currlevel)) {
                   2155:                 $ineffect = 1;
                   2156:             }
                   2157:         }
                   2158:     }
                   2159:     $r->print('<td style="background-color:'.($ineffect?'#AAFFAA':$defbg).
1.419     bisitz   2160:               ';" align="center">');
1.437     raeburn  2161:     my $nolink = 0;
1.568     raeburn  2162:     if ($readonly) {
1.552     raeburn  2163:         $nolink = 1;
1.568     raeburn  2164:     } else { 
1.578     raeburn  2165:         if ($which == 14 || $which == 15 || $mprefix =~ /mapalias\&$/) {
1.553     raeburn  2166:             $nolink = 1;
1.568     raeburn  2167:         } elsif (($env{'request.course.sec'} ne '') && ($which > 12)) {
1.533     raeburn  2168:             $nolink = 1;
1.568     raeburn  2169:         } elsif ($which == 5 || $which ==  6 || $which == 7 || $which == 8) {
                   2170:             if ($noeditgrp) {
                   2171:                 $nolink = 1;
                   2172:             }
                   2173:         } elsif ($mprefix =~ /availablestudent\&$/) {
1.599     raeburn  2174:             $nolink = 1;
1.568     raeburn  2175:         } elsif ($mprefix =~ /examcode\&$/) {
                   2176:             unless ($which == 2) {
                   2177:                 $nolink = 1;
                   2178:             }
1.533     raeburn  2179:         }
1.437     raeburn  2180:     }
                   2181:     if ($nolink) {
1.577     raeburn  2182:         my ($parmname)=((split(/\&/,$mprefix))[1]=~/\_([^\_]+)$/);
1.593     raeburn  2183:         $r->print(&valout($currval,$currtype));
1.114     www      2184:     } else {
1.578     raeburn  2185:         $r->print(&plink($currtype,
                   2186:                          $$display{$value},$currval,
1.588     raeburn  2187:                          $mprefix.$currlevel,'parmform.pres','psub',$recursive,
                   2188:                          $extra));
1.114     www      2189:     }
                   2190:     $r->print('</td>'."\n");
1.57      albertel 2191: }
                   2192: 
1.561     damieng  2193: # Returns HTML and other info for the cell added when a user is selected
                   2194: # and that user is in several groups. This is the cell with the title "Control by other group".
                   2195: #
                   2196: # @param {string} $what - parameter part.'.'.parameter name
                   2197: # @param {string} $rid - resource id
                   2198: # @param {string} $cgroup - group name
                   2199: # @param {string} $defbg - cell background color
                   2200: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   2201: # @param {integer} $result - level
                   2202: # @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db)
1.582     raeburn  2203: # @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  2204: sub check_other_groups {
                   2205:     my ($what,$rid,$cgroup,$defbg,$usersgroups,$result,$courseopt) = @_;
1.275     raeburn  2206:     my $courseid = $env{'request.course.id'};
                   2207:     my $output;
                   2208:     my $symb = &symbcache($rid);
                   2209:     my $symbparm=$symb.'.'.$what;
                   2210:     my $map=(&Apache::lonnet::decode_symb($symb))[0];
1.556     raeburn  2211:     my $recurseparm=$map.'___(rec).'.$what; 
1.275     raeburn  2212:     my $mapparm=$map.'___(all).'.$what;
                   2213:     my ($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype) =
1.556     raeburn  2214:           &parm_control_group($courseid,$usersgroups,$symbparm,$mapparm,
                   2215:                               $recurseparm,$what,$courseopt);
1.275     raeburn  2216:     my $bgcolor = $defbg;
1.582     raeburn  2217:     my ($grp_parm,$grp_is_rec);
1.446     bisitz   2218:     if (($coursereply) && ($cgroup ne $resultgroup)) {
1.582     raeburn  2219:         my ($parmname) = ($what =~ /\.([^.]+)$/);
1.275     raeburn  2220:         if ($result > 3) {
1.419     bisitz   2221:             $bgcolor = '#AAFFAA';
1.275     raeburn  2222:         }
1.593     raeburn  2223:         $grp_parm = &valout($coursereply,$resulttype);
1.419     bisitz   2224:         $output = '<td style="background-color:'.$bgcolor.';" align="center">';
1.275     raeburn  2225:         if ($resultgroup && $resultlevel) {
1.582     raeburn  2226:             if ($resultlevel eq 'recursive') {
                   2227:                 $resultlevel = 'map/folder';
                   2228:                 $grp_is_rec = 1;
                   2229:             }
                   2230:             $output .= '<small><b>'.$resultgroup.'</b> ('.$resultlevel.'): </small>'.$grp_parm.
                   2231:                        ($grp_is_rec?'<span class="LC_parm_recursive">'.&mt('recursive').'</span>':'');
                   2232:              
1.275     raeburn  2233:         } else {
                   2234:             $output .= '&nbsp;';
                   2235:         }
                   2236:         $output .= '</td>';
                   2237:     } else {
1.419     bisitz   2238:         $output .= '<td style="background-color:'.$bgcolor.';">&nbsp;</td>';
1.275     raeburn  2239:     }
1.582     raeburn  2240:     return ($coursereply,$output,$grp_parm,$resultgroup,$grp_is_rec);
1.275     raeburn  2241: }
                   2242: 
1.561     damieng  2243: # Looks for a group with a defined parameter for given user and parameter.
1.580     raeburn  2244: # Used by check_other_groups.
1.561     damieng  2245: #
                   2246: # @param {string} $courseid - the course id
                   2247: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   2248: # @param {string} $symbparm - end of the course parameter hash key for the group resource level
                   2249: # @param {string} $mapparm - end of the course parameter hash key for the group map/folder level
                   2250: # @param {string} $recurseparm - end of the course parameter hash key for the group recursive level
                   2251: # @param {string} $what - parameter part.'.'.parameter name
                   2252: # @param {hash reference} $courseopt - course parameters hash
                   2253: # @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  2254: sub parm_control_group {
1.556     raeburn  2255:     my ($courseid,$usersgroups,$symbparm,$mapparm,$recurseparm,$what,$courseopt) = @_;
1.275     raeburn  2256:     my ($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype);
                   2257:     my $grpfound = 0;
1.556     raeburn  2258:     my @levels = ($symbparm,$mapparm,$recurseparm,$what);
                   2259:     my @levelnames = ('resource','map/folder','recursive','general');
1.275     raeburn  2260:     foreach my $group (@{$usersgroups}) {
                   2261:         if ($grpfound) { last; }
                   2262:         for (my $i=0; $i<@levels; $i++) {
                   2263:             my $item = $courseid.'.['.$group.'].'.$levels[$i];
                   2264:             if (defined($$courseopt{$item})) {
                   2265:                 $coursereply = $$courseopt{$item};
                   2266:                 $resultitem = $item;
                   2267:                 $resultgroup = $group;
                   2268:                 $resultlevel = $levelnames[$i];
                   2269:                 $resulttype = $$courseopt{$item.'.type'};
                   2270:                 $grpfound = 1;
                   2271:                 last;
                   2272:             }
                   2273:         }
                   2274:     }
                   2275:     return($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype);
                   2276: }
1.201     www      2277: 
1.63      bowersj2 2278: 
                   2279: 
1.562     damieng  2280: # Extracts lots of information about all of the the course's resources into a variety of hashes, using lonnavmaps and lonnet::metadata.
                   2281: # All the parameters are references and are filled by the sub.
                   2282: #
1.566     damieng  2283: # @param {array reference} $ids - resource and map ids
                   2284: # @param {hash reference} $typep - hash resource/map id -> resource type (file extension)
                   2285: # @param {hash reference} $keyp - hash resource/map id -> comma-separated list of parameter keys from lonnet::metadata
1.562     damieng  2286: # @param {hash reference} $allparms - hash parameter name -> parameter title
                   2287: # @param {hash reference} $allparts - hash parameter part -> part title (a parameter part can be problem part.'_'.response id for response parameters)
1.566     damieng  2288: # @param {hash reference} $allmaps - hash map pc -> map src
                   2289: # @param {hash reference} $mapp - hash map pc or resource/map id -> enclosing map src
                   2290: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' for a map or resource symb for a resource
                   2291: # @param {hash reference} $maptitles - hash map pc or src -> map title (this should really be two separate hashes)
                   2292: # @param {hash reference} $uris - hash resource/map id -> resource src
1.562     damieng  2293: # @param {hash reference} $keyorder - hash parameter key -> appearance rank for this parameter when looking through every resource and every parameter, starting at 100 (integer)
                   2294: # @param {hash reference} $defkeytype - hash parameter name -> parameter type
1.608     raeburn  2295: # @param {string} $pssymb - resource symb (when a single resource is selected)
1.63      bowersj2 2296: sub extractResourceInformation {
                   2297:     my $ids = shift;
                   2298:     my $typep = shift;
                   2299:     my $keyp = shift;
                   2300:     my $allparms = shift;
                   2301:     my $allparts = shift;
                   2302:     my $allmaps = shift;
                   2303:     my $mapp = shift;
                   2304:     my $symbp = shift;
1.82      www      2305:     my $maptitles=shift;
1.196     www      2306:     my $uris=shift;
1.210     www      2307:     my $keyorder=shift;
1.211     www      2308:     my $defkeytype=shift;
1.603     raeburn  2309:     my $pssymb=shift;
1.196     www      2310: 
1.210     www      2311:     my $keyordercnt=100;
1.63      bowersj2 2312: 
1.196     www      2313:     my $navmap = Apache::lonnavmaps::navmap->new();
1.603     raeburn  2314:     return unless(ref($navmap));
                   2315:     my @allres;
                   2316:     if ($pssymb ne '') {
                   2317:         my $res = $navmap->getBySymb($pssymb);
                   2318:         if (ref($res)) {
                   2319:             @allres = ($res);
                   2320:         }
                   2321:     }
                   2322:     if (!@allres) { 
                   2323:         @allres=$navmap->retrieveResources(undef,undef,1,undef,1);
                   2324:     }
1.196     www      2325:     foreach my $resource (@allres) {
1.480     amueller 2326:         my $id=$resource->id();
1.196     www      2327:         my ($mapid,$resid)=split(/\./,$id);
1.480     amueller 2328:         if ($mapid eq '0') { next; }
                   2329:         $$ids[$#$ids+1]=$id;
                   2330:         my $srcf=$resource->src();
                   2331:         $srcf=~/\.(\w+)$/;
                   2332:         $$typep{$id}=$1;
1.584     raeburn  2333:         my $toolsymb;
                   2334:         if ($srcf =~ /ext\.tool$/) {
                   2335:             $toolsymb = $resource->symb();
                   2336:         }
1.480     amueller 2337:         $$keyp{$id}='';
1.196     www      2338:         $$uris{$id}=$srcf;
1.512     foxr     2339: 
1.584     raeburn  2340:         foreach my $key (split(/\,/,&Apache::lonnet::metadata($srcf,'allpossiblekeys',$toolsymb))) {
1.480     amueller 2341:             next if ($key!~/^parameter_/);
1.363     albertel 2342: 
1.209     www      2343: # Hidden parameters
1.584     raeburn  2344:             next if (&Apache::lonnet::metadata($srcf,$key.'.hidden',$toolsymb) eq 'parm');
1.209     www      2345: #
                   2346: # allparms is a hash of parameter names
                   2347: #
1.584     raeburn  2348:             my $name=&Apache::lonnet::metadata($srcf,$key.'.name',$toolsymb);
1.480     amueller 2349:             if (!exists($$allparms{$name}) || $$allparms{$name} =~ m/^\s*$/ ) {
                   2350:                 my ($display,$parmdis);
                   2351:                 $display = &standard_parameter_names($name);
                   2352:                 if ($display eq '') {
1.584     raeburn  2353:                     $display= &Apache::lonnet::metadata($srcf,$key.'.display',$toolsymb);
1.480     amueller 2354:                     $parmdis = $display;
                   2355:                     $parmdis =~ s/\s*\[Part.*$//g;
                   2356:                 } else {
                   2357:                     $parmdis = &mt($display);
                   2358:                 }
                   2359:                 $$allparms{$name}=$parmdis;
                   2360:                 if (ref($defkeytype)) {
                   2361:                     $$defkeytype{$name}=
1.584     raeburn  2362:                     &Apache::lonnet::metadata($srcf,$key.'.type',$toolsymb);
1.480     amueller 2363:                 }
                   2364:             }
1.363     albertel 2365: 
1.209     www      2366: #
                   2367: # allparts is a hash of all parts
                   2368: #
1.584     raeburn  2369:             my $part= &Apache::lonnet::metadata($srcf,$key.'.part',$toolsymb);
1.480     amueller 2370:             $$allparts{$part} = &mt('Part: [_1]',$part);
1.209     www      2371: #
                   2372: # Remember all keys going with this resource
                   2373: #
1.480     amueller 2374:             if ($$keyp{$id}) {
                   2375:                 $$keyp{$id}.=','.$key;
                   2376:             } else {
                   2377:                 $$keyp{$id}=$key;
                   2378:             }   
1.210     www      2379: #
                   2380: # Put in order
1.446     bisitz   2381: #
1.480     amueller 2382:             unless ($$keyorder{$key}) {
                   2383:                 $$keyorder{$key}=$keyordercnt;
                   2384:                 $keyordercnt++;
                   2385:             }
1.473     amueller 2386:         }
                   2387: 
                   2388: 
1.480     amueller 2389:         if (!exists($$mapp{$mapid})) {
                   2390:             $$mapp{$id}=
                   2391:             &Apache::lonnet::declutter($resource->enclosing_map_src());
                   2392:             $$mapp{$mapid}=$$mapp{$id};
                   2393:             $$allmaps{$mapid}=$$mapp{$id};
                   2394:             if ($mapid eq '1') {
1.532     raeburn  2395:                 $$maptitles{$mapid}=&mt('Main Content');
1.480     amueller 2396:             } else {
                   2397:                 $$maptitles{$mapid}=&Apache::lonnet::gettitle($$mapp{$id});
                   2398:             }
                   2399:             $$maptitles{$$mapp{$id}}=$$maptitles{$mapid};
1.556     raeburn  2400:             $$symbp{$mapid}=$$mapp{$id}.'___(all)';  # Added in rev. 1.57, but seems not to be used.
                   2401:                                                      # Lines 1038 and 1114 which use $symbp{$mapid}
                   2402:                                                      # are commented out in rev. 1.57
1.473     amueller 2403:         } else {
1.480     amueller 2404:             $$mapp{$id} = $$mapp{$mapid};
1.473     amueller 2405:         }
1.480     amueller 2406:         $$symbp{$id}=&Apache::lonnet::encode_symb($$mapp{$id},$resid,$srcf);
1.63      bowersj2 2407:     }
                   2408: }
                   2409: 
1.582     raeburn  2410: sub get_recursive {
                   2411:     my ($recurseup,$resdata,$what,$prefix) = @_; 
                   2412:     if ((ref($resdata) eq 'HASH') && (ref($recurseup) eq 'ARRAY')) {
                   2413:         foreach my $item (@{$recurseup}) {
                   2414:             my $norecursechk=$prefix.'.'.$item.'___(all).'.$what;
                   2415:             if (defined($resdata->{$norecursechk})) {
                   2416:                 if ($what =~ /\.(encrypturl|hiddenresource)$/) {
                   2417:                     my $type = $resdata->{$norecursechk.'.type'};
                   2418:                     return [$resdata->{$norecursechk},$type,$item];
                   2419:                 } else {
                   2420:                     last;
                   2421:                 }
                   2422:             }
                   2423:             my $recursechk=$prefix.'.'.$item.'___(rec).'.$what;
                   2424:             if (defined($resdata->{$recursechk})) {
                   2425:                 my $type = $resdata->{$recursechk.'.type'};
                   2426:                 return [$resdata->{$recursechk},$type,$item];
                   2427:             }
                   2428:         }
                   2429:     }
                   2430:     return;
                   2431: }
                   2432: 
1.208     www      2433: 
1.562     damieng  2434: # Tells if a parameter type is a date.
                   2435: #
                   2436: # @param {string} type - parameter type
                   2437: # @returns{boolean} - true if it is a date
1.213     www      2438: sub isdateparm {
                   2439:     my $type=shift;
                   2440:     return (($type=~/^date/) && (!($type eq 'date_interval')));
                   2441: }
                   2442: 
1.589     raeburn  2443: # Determine if parameter type is specialized string type (i.e.,
                   2444: # not just string or string_yesno.  
                   2445: 
                   2446: sub is_specialstring {
                   2447:     my $type=shift;
1.603     raeburn  2448:     return (($type=~/^string_/) && ($type ne 'string_yesno'));
1.589     raeburn  2449: }
                   2450: 
1.562     damieng  2451: # Prints the HTML and Javascript to select parameters, with various shortcuts.
1.468     amueller 2452: #
1.581     raeburn  2453: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      2454: sub parmmenu {
1.581     raeburn  2455:     my ($r)=@_;
1.208     www      2456:     $r->print(<<ENDSCRIPT);
                   2457: <script type="text/javascript">
1.454     bisitz   2458: // <![CDATA[
1.208     www      2459:     function checkall(value, checkName) {
1.453     schualex 2460: 
                   2461:         var li = "_li";
                   2462:         var displayOverview = "";
                   2463:         
                   2464:         if (value == false) {
                   2465:             displayOverview = "none"
                   2466:         }
                   2467: 
1.562     damieng  2468:         for (i=0; i<document.forms.parmform.elements.length; i++) {
1.208     www      2469:             ele = document.forms.parmform.elements[i];
                   2470:             if (ele.name == checkName) {
                   2471:                 document.forms.parmform.elements[i].checked=value;
                   2472:             }
                   2473:         }
                   2474:     }
1.210     www      2475: 
                   2476:     function checkthis(thisvalue, checkName) {
1.562     damieng  2477:         for (i=0; i<document.forms.parmform.elements.length; i++) {
1.210     www      2478:             ele = document.forms.parmform.elements[i];
                   2479:             if (ele.name == checkName) {
1.562     damieng  2480:                 if (ele.value == thisvalue) {
                   2481:                     document.forms.parmform.elements[i].checked=true;
                   2482:                 }
1.210     www      2483:             }
                   2484:         }
                   2485:     }
                   2486: 
                   2487:     function checkdates() {
1.562     damieng  2488:         checkthis('duedate','pscat');
                   2489:         checkthis('opendate','pscat');
                   2490:         checkthis('answerdate','pscat');
1.218     www      2491:     }
                   2492: 
                   2493:     function checkdisset() {
1.562     damieng  2494:         checkthis('discussend','pscat');
                   2495:         checkthis('discusshide','pscat');
                   2496:         checkthis('discussvote','pscat');
1.218     www      2497:     }
                   2498: 
                   2499:     function checkcontdates() {
1.562     damieng  2500:         checkthis('contentopen','pscat');
                   2501:         checkthis('contentclose','pscat');
1.218     www      2502:     }
1.446     bisitz   2503: 
1.210     www      2504:     function checkvisi() {
1.562     damieng  2505:         checkthis('hiddenresource','pscat');
                   2506:         checkthis('encrypturl','pscat');
                   2507:         checkthis('problemstatus','pscat');
                   2508:         checkthis('contentopen','pscat');
                   2509:         checkthis('opendate','pscat');
1.210     www      2510:     }
                   2511: 
                   2512:     function checkparts() {
1.562     damieng  2513:         checkthis('hiddenparts','pscat');
                   2514:         checkthis('display','pscat');
                   2515:         checkthis('ordered','pscat');
1.210     www      2516:     }
                   2517: 
                   2518:     function checkstandard() {
                   2519:         checkall(false,'pscat');
1.562     damieng  2520:         checkdates();
                   2521:         checkthis('weight','pscat');
                   2522:         checkthis('maxtries','pscat');
                   2523:         checkthis('type','pscat');
                   2524:         checkthis('problemstatus','pscat');
1.210     www      2525:     }
                   2526: 
1.454     bisitz   2527: // ]]>
1.208     www      2528: </script>
                   2529: ENDSCRIPT
1.453     schualex 2530: 
1.491     bisitz   2531:     $r->print('<hr />');
1.581     raeburn  2532:     &shortCuts($r);
1.491     bisitz   2533:     $r->print('<hr />');
1.453     schualex 2534: }
1.562     damieng  2535: 
                   2536: # Returns parameter categories.
                   2537: #
                   2538: # @returns {hash} - category name -> title in English
1.465     amueller 2539: sub categories {
                   2540:     return ('time_settings' => 'Time Settings',
                   2541:     'grading' => 'Grading',
                   2542:     'tries' => 'Tries',
                   2543:     'problem_appearance' => 'Problem Appearance',
                   2544:     'behaviour_of_input_fields' => 'Behaviour of Input Fields',
                   2545:     'hiding' => 'Hiding',
                   2546:     'high_level_randomization' => 'High Level Randomization',
                   2547:     'slots' => 'Slots',
                   2548:     'file_submission' => 'File Submission',
                   2549:     'misc' => 'Miscellaneous' ); 
                   2550: }
                   2551: 
1.562     damieng  2552: # Returns the category for each parameter.
                   2553: #
                   2554: # @returns {hash} - parameter name -> category name
1.465     amueller 2555: sub lookUpTableParameter {
                   2556:  
                   2557:     return ( 
                   2558:         'opendate' => 'time_settings',
                   2559:         'duedate' => 'time_settings',
                   2560:         'answerdate' => 'time_settings',
1.622   ! raeburn  2561:         'grace' => 'time_settings',
1.465     amueller 2562:         'interval' => 'time_settings',
                   2563:         'contentopen' => 'time_settings',
                   2564:         'contentclose' => 'time_settings',
                   2565:         'discussend' => 'time_settings',
1.560     damieng  2566:         'printstartdate' => 'time_settings',
                   2567:         'printenddate' => 'time_settings',
1.465     amueller 2568:         'weight' => 'grading',
                   2569:         'handgrade' => 'grading',
                   2570:         'maxtries' => 'tries',
                   2571:         'hinttries' => 'tries',
1.503     raeburn  2572:         'randomizeontries' => 'tries',
1.465     amueller 2573:         'type' => 'problem_appearance',
                   2574:         'problemstatus' => 'problem_appearance',
                   2575:         'display' => 'problem_appearance',
                   2576:         'ordered' => 'problem_appearance',
                   2577:         'numbubbles' => 'problem_appearance',
                   2578:         'tol' => 'behaviour_of_input_fields',
                   2579:         'sig' => 'behaviour_of_input_fields',
                   2580:         'turnoffunit' => 'behaviour_of_input_fields',
                   2581:         'hiddenresource' => 'hiding',
                   2582:         'hiddenparts' => 'hiding',
                   2583:         'discusshide' => 'hiding',
                   2584:         'buttonshide' => 'hiding',
                   2585:         'turnoffeditor' => 'hiding',
                   2586:         'encrypturl' => 'hiding',
1.587     raeburn  2587:         'deeplink' => 'hiding',
1.465     amueller 2588:         'randomorder' => 'high_level_randomization',
                   2589:         'randompick' => 'high_level_randomization',
                   2590:         'available' => 'slots',
                   2591:         'useslots' => 'slots',
                   2592:         'availablestudent' => 'slots',
                   2593:         'uploadedfiletypes' => 'file_submission',
                   2594:         'maxfilesize' => 'file_submission',
                   2595:         'cssfile' => 'misc',
                   2596:         'mapalias' => 'misc',
                   2597:         'acc' => 'misc',
                   2598:         'maxcollaborators' => 'misc',
                   2599:         'scoreformat' => 'misc',
1.514     raeburn  2600:         'lenient' => 'grading',
1.519     raeburn  2601:         'retrypartial' => 'tries',
1.521     raeburn  2602:         'discussvote'  => 'misc',
1.621     raeburn  2603:         'texdisplay' => 'misc',
1.584     raeburn  2604:         'examcode' => 'high_level_randomization',
1.575     raeburn  2605:     );
1.465     amueller 2606: }
                   2607: 
1.562     damieng  2608: # Adds the given parameter name to an array of arrays listing all parameters for each category.
                   2609: #
                   2610: # @param {string} $name - parameter name
                   2611: # @param {array reference} $catList - array reference category name -> array reference of parameter names
1.465     amueller 2612: sub whatIsMyCategory {
                   2613:     my $name = shift;
                   2614:     my $catList = shift;
                   2615:     my @list;
                   2616:     my %lookUpList = &lookUpTableParameter; #Initilize the lookupList
                   2617:     my $cat = $lookUpList{$name};
                   2618:     if (defined($cat)) {
                   2619:         if (!defined($$catList{$cat})){
                   2620:             push @list, ($name);
                   2621:             $$catList{$cat} = \@list;
                   2622:         } else {
                   2623:             push @{${$catList}{$cat}}, ($name);     
                   2624:         }
                   2625:     } else {
                   2626:         if (!defined($$catList{'misc'})){
                   2627:             push @list, ($name);
                   2628:             $$catList{'misc'} = \@list;
                   2629:         } else {
                   2630:             push @{${$catList}{'misc'}}, ($name);     
                   2631:         }
                   2632:     }        
                   2633: }
                   2634: 
1.562     damieng  2635: # Sorts parameter names based on appearance order.
                   2636: #
                   2637: # @param {array reference} name - array reference of parameter names
                   2638: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   2639: # @returns {Array} - array of parameter names
1.465     amueller 2640: sub keysindisplayorderCategory {
                   2641:     my ($name,$keyorder)=@_;
                   2642:     return sort {
1.473     amueller 2643:         $$keyorder{'parameter_0_'.$a} <=> $$keyorder{'parameter_0_'.$b}; 
1.465     amueller 2644:     } ( @{$name});
                   2645: }
                   2646: 
1.562     damieng  2647: # Returns a hash category name -> order, starting at 1 (integer)
                   2648: #
                   2649: # @returns {hash}
1.467     amueller 2650: sub category_order {
                   2651:     return (
                   2652:         'time_settings' => 1,
                   2653:         'grading' => 2,
                   2654:         'tries' => 3,
                   2655:         'problem_appearance' => 4,
                   2656:         'hiding' => 5,
                   2657:         'behaviour_of_input_fields' => 6,
                   2658:         'high_level_randomization'  => 7,
                   2659:         'slots' => 8,
                   2660:         'file_submission' => 9,
                   2661:         'misc' => 10
                   2662:     );
                   2663: 
                   2664: }
1.453     schualex 2665: 
1.562     damieng  2666: # Prints HTML to let the user select parameters, from a list of all parameters organized by category.
                   2667: #
                   2668: # @param {Apache2::RequestRec} $r - the Apache request
                   2669: # @param {hash reference} $allparms - hash parameter name -> parameter title
                   2670: # @param {array reference} $pscat - list of selected parameter names
                   2671: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
1.453     schualex 2672: sub parmboxes {
                   2673:     my ($r,$allparms,$pscat,$keyorder)=@_;
1.548     raeburn  2674:     my %categories = &categories();
1.467     amueller 2675:     my %category_order = &category_order();
1.465     amueller 2676:     my %categoryList = (
                   2677:         'time_settings' => [],
                   2678:         'grading' => [],
                   2679:         'tries' => [],
                   2680:         'problem_appearance' => [],
                   2681:         'behaviour_of_input_fields' => [],
                   2682:         'hiding' => [],
                   2683:         'high_level_randomization' => [],
                   2684:         'slots' => [],
                   2685:         'file_submission' => [],
                   2686:         'misc' => [],
1.489     bisitz   2687:     );
1.510     www      2688: 
1.548     raeburn  2689:     foreach my $tempparameter (keys(%$allparms)) {
1.465     amueller 2690:         &whatIsMyCategory($tempparameter, \%categoryList);
                   2691:     }
1.453     schualex 2692:     #part to print the parm-list
1.618     raeburn  2693:     $Text::Wrap::columns=60;
                   2694:     $Text::Wrap::separator='<br />';
1.536     raeburn  2695:     foreach my $key (sort { $category_order{$a} <=> $category_order{$b} } keys(%categoryList)) {
                   2696:         next if (@{$categoryList{$key}} == 0);
                   2697:         next if ($key eq '');
                   2698:         $r->print('<div class="LC_Box LC_400Box">'
                   2699:                  .'<h4 class="LC_hcell">'.&mt($categories{$key}).'</h4>'."\n");
                   2700:         foreach my $tempkey (&keysindisplayorderCategory($categoryList{$key},$keyorder)) {
1.575     raeburn  2701:             next if ($tempkey eq '');
1.536     raeburn  2702:             $r->print('<span class="LC_nobreak">'
                   2703:                      .'<label><input type="checkbox" name="pscat" '
                   2704:                      .'value="'.$tempkey.'" ');
                   2705:             if ($$pscat[0] eq "all" || grep $_ eq $tempkey, @{$pscat}) {
                   2706:                 $r->print( ' checked="checked"');
                   2707:             }
1.617     raeburn  2708:             $r->print(' />'.($$allparms{$tempkey}=~/\S/ ? 
                   2709:                              Text::Wrap::wrap('','&nbsp;'x4,$$allparms{$tempkey})
                   2710:                              : $tempkey)
1.536     raeburn  2711:                      .'</label></span><br />'."\n");
1.465     amueller 2712:         }
1.536     raeburn  2713:         $r->print('</div>');
1.465     amueller 2714:     }
1.536     raeburn  2715:     $r->print("\n");
1.453     schualex 2716: }
1.562     damieng  2717: 
                   2718: # Prints HTML with shortcuts to select groups of parameters in one click, or deselect all.
1.468     amueller 2719: #
1.562     damieng  2720: # @param {Apache2::RequestRec} $r - the Apache request
1.453     schualex 2721: sub shortCuts {
1.581     raeburn  2722:     my ($r)=@_;
1.453     schualex 2723: 
1.491     bisitz   2724:     # Parameter Selection
                   2725:     $r->print(
                   2726:         &Apache::lonhtmlcommon::start_funclist(&mt('Parameter Selection'))
                   2727:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2728:             '<a href="javascript:checkall(true, \'pscat\')">'.&mt('Select All').'</a>')
                   2729:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2730:             '<a href="javascript:checkstandard()">'.&mt('Select Common Only').'</a>')
                   2731:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2732:             '<a href="javascript:checkall(false, \'pscat\')">'.&mt('Unselect All').'</a>')
                   2733:        .&Apache::lonhtmlcommon::end_funclist()
                   2734:     );
                   2735: 
                   2736:     # Add Selection for...
                   2737:     $r->print(
                   2738:         &Apache::lonhtmlcommon::start_funclist(&mt('Add Selection for...'))
                   2739:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2740:             '<a href="javascript:checkdates()">'.&mt('Problem Dates').'</a>')
                   2741:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2742:             '<a href="javascript:checkcontdates()">'.&mt('Content Dates').'</a>')
                   2743:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2744:             '<a href="javascript:checkdisset()">'.&mt('Discussion Settings').'</a>')
                   2745:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2746:             '<a href="javascript:checkvisi()">'.&mt('Visibilities').'</a>')
                   2747:        .&Apache::lonhtmlcommon::add_item_funclist(
                   2748:             '<a href="javascript:checkparts()">'.&mt('Part Parameters').'</a>')
                   2749:        .&Apache::lonhtmlcommon::end_funclist()
                   2750:     );
1.208     www      2751: }
                   2752: 
1.562     damieng  2753: # Prints HTML to select parts to view (except for the title).
                   2754: # Used by table and overview modes.
                   2755: #
                   2756: # @param {Apache2::RequestRec} $r - the Apache request
                   2757: # @param {hash reference} $allparts - hash parameter part -> part title
                   2758: # @param {array reference} $psprt - list of selected parameter parts
1.209     www      2759: sub partmenu {
1.446     bisitz   2760:     my ($r,$allparts,$psprt)=@_;
1.523     raeburn  2761:     my $selsize = 1+scalar(keys(%{$allparts}));
                   2762:     if ($selsize > 8) {
                   2763:         $selsize = 8;
                   2764:     }
1.446     bisitz   2765: 
1.523     raeburn  2766:     $r->print('<select multiple="multiple" name="psprt" size="'.$selsize.'">');
1.208     www      2767:     $r->print('<option value="all"');
1.562     damieng  2768:     $r->print(' selected="selected"') unless (@{$psprt}); # useless, the array is never empty
1.208     www      2769:     $r->print('>'.&mt('All Parts').'</option>');
                   2770:     my %temphash=();
                   2771:     foreach (@{$psprt}) { $temphash{$_}=1; }
1.234     albertel 2772:     foreach my $tempkey (sort {
1.560     damieng  2773:                 if ($a==$b) { return ($a cmp $b) } else { return ($a <=> $b); }
                   2774:             } keys(%{$allparts})) {
                   2775:         unless ($tempkey =~ /\./) {
                   2776:             $r->print('<option value="'.$tempkey.'"');
                   2777:             if ($$psprt[0] eq "all" ||  $temphash{$tempkey}) {
                   2778:                 $r->print(' selected="selected"');
                   2779:             }
                   2780:             $r->print('>'.$$allparts{$tempkey}.'</option>');
1.473     amueller 2781:         }
1.208     www      2782:     }
1.446     bisitz   2783:     $r->print('</select>');
1.209     www      2784: }
                   2785: 
1.562     damieng  2786: # Prints HTML to select a user and/or a group.
                   2787: # Used by table mode.
                   2788: #
                   2789: # @param {Apache2::RequestRec} $r - the Apache request
                   2790: # @param {string} $uname - selected user name
                   2791: # @param {string} $id - selected Student/Employee ID
                   2792: # @param {string} $udom - selected user domain
                   2793: # @param {string} $csec - selected section name
                   2794: # @param {string} $cgroup - selected group name
                   2795: # @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general')
                   2796: # @param {array reference} $usersgroups - list of groups the user belongs to, if any
                   2797: # @param {string} $pssymb - resource symb (when a single resource is selected)
1.209     www      2798: sub usermenu {
1.553     raeburn  2799:     my ($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,$usersgroups,$pssymb)=@_;
1.209     www      2800:     my $chooseopt=&Apache::loncommon::select_dom_form($udom,'udom').' '.
1.596     raeburn  2801:                   &Apache::loncommon::selectstudent_link('parmform','uname','udom','condition').
                   2802:                   &Apache::lonhtmlcommon::scripttag(<<ENDJS);
                   2803: function setCourseadv(form,caller) {
                   2804:     if (caller.value == 'st') {
                   2805:         form.courseadv.value = 'none';
                   2806:     } else {
                   2807:         form.courseadv.value = '';
                   2808:     }
                   2809:     return;
                   2810: }
                   2811: ENDJS
1.412     bisitz   2812: 
1.596     raeburn  2813:     my (%chkroles,$stuonly,$courseadv);
                   2814:     if ($env{'form.userroles'} eq 'any') {
                   2815:         $chkroles{'any'} = ' checked="checked"';
                   2816:     } else {
                   2817:         $chkroles{'st'} = ' checked="checked"';
                   2818:         $courseadv = 'none';
                   2819:     }
                   2820:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   2821:     if ($crstype eq 'Community') {
                   2822:         $stuonly = &mt('member only');
                   2823:     } else {
                   2824:         $stuonly = &mt('student only');
                   2825:     }
                   2826:     $chooseopt .= '<br /><span class="LC_cusr_subheading">'.
                   2827:                   &mt("User's role").':&nbsp;'.
                   2828:                   '<label><input type="radio" name="userroles" value="st"'.$chkroles{'st'}.' onclick="setCourseadv(this.form,this);" />'.
                   2829:                   $stuonly.'</label>&nbsp;&nbsp;'.
                   2830:                   '<label><input type="radio" name="userroles" value="any"'.$chkroles{'any'}.' onclick="setCourseadv(this.form,this);" />'.
                   2831:                   &mt('any role').'</label><input type="hidden" id="courseadv" name="courseadv" value="'.$courseadv.'" /></span>';
1.209     www      2832:     my $sections='';
1.300     albertel 2833:     my %sectionhash = &Apache::loncommon::get_sections();
                   2834: 
1.269     raeburn  2835:     my $groups;
1.553     raeburn  2836:     my %grouphash;
                   2837:     if (($pssymb) || &Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   2838:         %grouphash = &Apache::longroup::coursegroups();
                   2839:     } elsif ($env{'request.course.groups'} ne '') {
1.585     raeburn  2840:         map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'});
1.553     raeburn  2841:     }
1.299     albertel 2842: 
1.412     bisitz   2843:     my $g_s_header='';
                   2844:     my $g_s_footer='';
1.446     bisitz   2845: 
1.552     raeburn  2846:     my $currsec = $env{'request.course.sec'};
                   2847:     if ($currsec) {
                   2848:         $sections=&mt('Section:').' '.$currsec;
                   2849:         if (%grouphash) {
                   2850:             $sections .= ';'.('&nbsp;' x2);
                   2851:         }
                   2852:     } elsif (%sectionhash && $currsec eq '') {
1.412     bisitz   2853:         $sections=&mt('Section:').' <select name="csec"';
1.299     albertel 2854:         if (%grouphash && $parmlev ne 'full') {
1.269     raeburn  2855:             $sections .= qq| onchange="group_or_section('csec')" |;
                   2856:         }
                   2857:         $sections .= '>';
1.548     raeburn  2858:     foreach my $section ('',sort(keys(%sectionhash))) {
1.473     amueller 2859:         $sections.='<option value="'.$section.'" '.
                   2860:         ($section eq $csec?'selected="selected"':'').'>'.$section.
1.275     raeburn  2861:                                                               '</option>';
1.209     www      2862:         }
                   2863:         $sections.='</select>';
1.269     raeburn  2864:     }
1.412     bisitz   2865: 
1.552     raeburn  2866:     if (%sectionhash && %grouphash && $parmlev ne 'full' && $currsec eq '') {
1.412     bisitz   2867:         $sections .= '&nbsp;'.&mt('or').'&nbsp;';
1.269     raeburn  2868:         $sections .= qq|
                   2869: <script type="text/javascript">
1.454     bisitz   2870: // <![CDATA[
1.269     raeburn  2871: function group_or_section(caller) {
                   2872:    if (caller == "cgroup") {
                   2873:        if (document.parmform.cgroup.selectedIndex != 0) {
                   2874:            document.parmform.csec.selectedIndex = 0;
                   2875:        }
                   2876:    } else {
                   2877:        if (document.parmform.csec.selectedIndex != 0) {
                   2878:            document.parmform.cgroup.selectedIndex = 0;
                   2879:        }
                   2880:    }
                   2881: }
1.454     bisitz   2882: // ]]>
1.269     raeburn  2883: </script>
                   2884: |;
1.554     raeburn  2885:     } else {
1.269     raeburn  2886:         $sections .= qq|
                   2887: <script type="text/javascript">
1.454     bisitz   2888: // <![CDATA[
1.269     raeburn  2889: function group_or_section(caller) {
                   2890:     return;
                   2891: }
1.454     bisitz   2892: // ]]>
1.269     raeburn  2893: </script>
                   2894: |;
1.446     bisitz   2895:     }
1.299     albertel 2896: 
                   2897:     if (%grouphash) {
1.597     raeburn  2898:         $groups=&mt('Group').': <select name="cgroup"';
1.552     raeburn  2899:         if (%sectionhash && $env{'form.action'} eq 'settable' && $currsec eq '') {
1.269     raeburn  2900:             $groups .= qq| onchange="group_or_section('cgroup')" |;
                   2901:         }
                   2902:         $groups .= '>';
1.548     raeburn  2903:         foreach my $grp ('',sort(keys(%grouphash))) {
1.275     raeburn  2904:             $groups.='<option value="'.$grp.'" ';
                   2905:             if ($grp eq $cgroup) {
                   2906:                 unless ((defined($uname)) && ($grp eq '')) {
                   2907:                     $groups .=  'selected="selected" ';
                   2908:                 }
                   2909:             } elsif (!defined($cgroup)) {
                   2910:                 if (@{$usersgroups} == 1) {
                   2911:                     if ($grp eq $$usersgroups[0]) {
                   2912:                         $groups .=  'selected="selected" ';
                   2913:                     }
                   2914:                 }
                   2915:             }
                   2916:             $groups .= '>'.$grp.'</option>';
1.269     raeburn  2917:         }
                   2918:         $groups.='</select>';
                   2919:     }
1.412     bisitz   2920: 
1.445     neumanie 2921:     if (%sectionhash || %grouphash) {
1.446     bisitz   2922:         $r->print(&Apache::lonhtmlcommon::row_title(&mt('Group/Section')));
                   2923:         $r->print($sections.$groups);
1.448     bisitz   2924:         $r->print(&Apache::lonhtmlcommon::row_closure());
1.554     raeburn  2925:     } else {
                   2926:         $r->print($sections); 
1.445     neumanie 2927:     }
1.446     bisitz   2928: 
                   2929:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('User')));
1.443     neumanie 2930:     $r->print(&mt('For User [_1] or Student/Employee ID [_2] at Domain [_3]'
1.412     bisitz   2931:                  ,'<input type="text" value="'.$uname.'" size="12" name="uname" />'
                   2932:                  ,'<input type="text" value="'.$id.'" size="12" name="id" /> '
1.446     bisitz   2933:                  ,$chooseopt));
1.209     www      2934: }
                   2935: 
1.562     damieng  2936: # Prints HTML to select parameters from a list of all parameters.
                   2937: # Uses parmmenu and parmboxes.
                   2938: # Used by table and overview modes.
1.468     amueller 2939: #
1.562     damieng  2940: # @param {Apache2::RequestRec} $r - the Apache request
                   2941: # @param {hash reference} $allparms - hash parameter name -> parameter title
                   2942: # @param {array reference} $pscat - list of selected parameter names
                   2943: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   2944: # @param {string} [$divid] - name used to give an id to the HTML element for the scroll box
1.209     www      2945: sub displaymenu {
1.581     raeburn  2946:     my ($r,$allparms,$pscat,$keyorder,$divid)=@_;
1.510     www      2947: 
1.445     neumanie 2948:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.510     www      2949:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parameters to View')));
                   2950: 
1.581     raeburn  2951:     &parmmenu($r);
1.536     raeburn  2952:     $r->print(&Apache::loncommon::start_scrollbox('480px','440px','200px',$divid));
1.510     www      2953:     &parmboxes($r,$allparms,$pscat,$keyorder);
                   2954:     $r->print(&Apache::loncommon::end_scrollbox());
                   2955: 
                   2956:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.453     schualex 2957:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.510     www      2958:  
1.209     www      2959: }
                   2960: 
1.562     damieng  2961: # Prints HTML to select a map.
                   2962: # Used by table mode and overview mode.
                   2963: #
                   2964: # @param {Apache2::RequestRec} $r - the Apache request
1.566     damieng  2965: # @param {hash reference} $allmaps - hash map pc -> map src
                   2966: # @param {string} $pschp - selected map pc, or 'all'
1.562     damieng  2967: # @param {hash reference} $maptitles - hash map id or src -> map title
1.566     damieng  2968: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' or resource symb
1.610     raeburn  2969: # @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general')
1.445     neumanie 2970: sub mapmenu {
1.610     raeburn  2971:     my ($r,$allmaps,$pschp,$maptitles,$symbp,$parmlev)=@_;
1.468     amueller 2972:     my %allmaps_inverted = reverse %$allmaps;
1.461     neumanie 2973:     my $navmap = Apache::lonnavmaps::navmap->new();
                   2974:     my $tree=[];
                   2975:     my $treeinfo={};
                   2976:     if (defined($navmap)) {
1.499     raeburn  2977:         my $it=$navmap->getIterator(undef,undef,undef,1,1,undef);
1.461     neumanie 2978:         my $curRes;
                   2979:         my $depth = 0;
1.468     amueller 2980:         my %parent = ();
                   2981:         my $startcount = 5;
                   2982:         my $lastcontainer = $startcount;
                   2983: # preparing what is to show ...
1.461     neumanie 2984:         while ($curRes = $it->next()) {
                   2985:             if ($curRes == $it->BEGIN_MAP()) {
                   2986:                 $depth++;
1.468     amueller 2987:                 $parent{$depth}= $lastcontainer;
1.461     neumanie 2988:             }
                   2989:             if ($curRes == $it->END_MAP()) {
                   2990:                 $depth--;
1.468     amueller 2991:                 $lastcontainer = $parent{$depth};
1.461     neumanie 2992:             }
                   2993:             if (ref($curRes)) {
1.468     amueller 2994:                 my $symb = $curRes->symb();
                   2995:                 my $ressymb = $symb;
1.461     neumanie 2996:                 if (($curRes->is_sequence()) || ($curRes->is_page())) {
                   2997:                     my $type = 'sequence';
                   2998:                     if ($curRes->is_page()) {
                   2999:                         $type = 'page';
                   3000:                     }
                   3001:                     my $id= $curRes->id();
1.468     amueller 3002:                     my $srcf = $curRes->src();
                   3003:                     my $resource_name = &Apache::lonnet::gettitle($srcf);
                   3004:                     if(!exists($treeinfo->{$id})) {
                   3005:                         push(@$tree,$id);
1.473     amueller 3006:                         my $enclosing_map_folder = &Apache::lonnet::declutter($curRes->enclosing_map_src());        
1.468     amueller 3007:                         $treeinfo->{$id} = {
1.461     neumanie 3008:                                     depth => $depth,
                   3009:                                     type  => $type,
1.468     amueller 3010:                                     name  => $resource_name,
                   3011:                                     enclosing_map_folder => $enclosing_map_folder,
1.461     neumanie 3012:                                     };
1.462     neumanie 3013:                     }
1.461     neumanie 3014:                 }
                   3015:             }
                   3016:         }
1.462     neumanie 3017:     }
1.473     amueller 3018: # Show it ...    
1.610     raeburn  3019:     my $rowattr = ' id="mapmenu"';
                   3020:     if ($parmlev eq 'general') {
                   3021:         $rowattr .= ' style="display:none"';
                   3022:     }
                   3023:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Enclosing Map or Folder'),'','',$rowattr));
1.461     neumanie 3024:     if ((ref($tree) eq 'ARRAY') && (ref($treeinfo) eq 'HASH')) {
                   3025:         my $icon = '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" />';
1.497     bisitz   3026:         my $whitespace =
                   3027:             '<img src="'
                   3028:            .&Apache::loncommon::lonhttpdurl('/adm/lonIcons/whitespace_21.gif')
                   3029:            .'" alt="" />';
                   3030: 
1.498     bisitz   3031:         # Info about selectable folders/maps
                   3032:         $r->print(
                   3033:             '<div class="LC_info">'
1.508     www      3034:            .&mt('You can only select maps and folders which have modifiable settings.')
                   3035:            .' '.&Apache::loncommon::help_open_topic('Parameter_Set_Folder') 
1.498     bisitz   3036:            .'</div>'
                   3037:         );
                   3038: 
1.536     raeburn  3039:         $r->print(&Apache::loncommon::start_scrollbox('700px','680px','400px','mapmenuscroll'));
1.523     raeburn  3040:         $r->print(&Apache::loncommon::start_data_table(undef,'mapmenuinner'));
1.497     bisitz   3041: 
1.498     bisitz   3042:         # Display row: "All Maps or Folders"
                   3043:         $r->print(
1.523     raeburn  3044:             &Apache::loncommon::start_data_table_row(undef,'picklevel')
1.498     bisitz   3045:            .'<td>'
                   3046:            .'<label>'
                   3047:            .'<input type="radio" name="pschp"'
1.497     bisitz   3048:         );
                   3049:         $r->print(' checked="checked"') if ($pschp eq 'all' || !$pschp);
1.498     bisitz   3050:         $r->print(
                   3051:             ' value="all" />&nbsp;'.$icon.'&nbsp;'
                   3052:            .&mt('All Maps or Folders')
                   3053:            .'</label>'
                   3054:            .'<hr /></td>'
                   3055:            .&Apache::loncommon::end_data_table_row()
1.463     bisitz   3056:         );
1.497     bisitz   3057: 
1.532     raeburn  3058:         # Display row: "Main Content"
1.468     amueller 3059:         if (exists($$allmaps{1})) {
1.498     bisitz   3060:             $r->print(
                   3061:                 &Apache::loncommon::start_data_table_row()
                   3062:                .'<td>'
                   3063:                .'<label>'
                   3064:                .'<input type="radio" name="pschp" value="1"'
1.468     amueller 3065:             );
1.497     bisitz   3066:             $r->print(' checked="checked"') if ($pschp eq '1');
1.498     bisitz   3067:             $r->print(
                   3068:                 '/>&nbsp;'.$icon.'&nbsp;'
                   3069:                .$$maptitles{1}
                   3070:                .($$allmaps{1} !~/^uploaded/?' ['.$$allmaps{1}.']':'')
                   3071:                .'</label>'
                   3072:                .'</td>'
                   3073:                .&Apache::loncommon::end_data_table_row()
1.468     amueller 3074:             );
                   3075:         }
1.497     bisitz   3076: 
                   3077:         # Display rows for all course maps and folders
1.468     amueller 3078:         foreach my $id (@{$tree}) {
                   3079:             my ($mapid,$resid)=split(/\./,$id);
1.464     bisitz   3080:             # Indentation
1.468     amueller 3081:             my $depth = $treeinfo->{$id}->{'depth'};
1.464     bisitz   3082:             my $indent;
                   3083:             for (my $i = 0; $i < $depth; $i++) {
                   3084:                 $indent.= $whitespace;
                   3085:             }
1.461     neumanie 3086:             $icon =  '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" />';
1.468     amueller 3087:             if ($treeinfo->{$id}->{'type'} eq 'page') {
1.461     neumanie 3088:                 $icon = '<img src="/adm/lonIcons/navmap.page.open.gif" alt="" />';
                   3089:             }
1.468     amueller 3090:             my $symb_name = $$symbp{$id};
                   3091:             my ($front, $tail) = split (/___${resid}___/, $symb_name);
                   3092:             $symb_name = $tail;
1.498     bisitz   3093:             $r->print(
                   3094:                 &Apache::loncommon::start_data_table_row()
                   3095:                .'<td>'
                   3096:                .'<label>'
1.463     bisitz   3097:             );
1.498     bisitz   3098:             # Only offer radio button for folders/maps which can be parameterized
                   3099:             if ($allmaps_inverted{$symb_name}) {
                   3100:                 $r->print(
                   3101:                     '<input type ="radio" name="pschp"'
                   3102:                    .' value="'.$allmaps_inverted{$symb_name}.'"'
                   3103:                 );
                   3104:                 $r->print(' checked="checked"') if ($allmaps_inverted{$symb_name} eq $pschp);
                   3105:                 $r->print('/>');
                   3106:             } else {
                   3107:                 $r->print($whitespace);
1.461     neumanie 3108:             }
1.498     bisitz   3109:             $r->print(
                   3110:                 $indent.$icon.'&nbsp;'
                   3111:                .$treeinfo->{$id}->{name}
                   3112:                .($$allmaps{$mapid}!~/^uploaded/?' ['.$$allmaps{$mapid}.']':'')
                   3113:                .'</label>'
                   3114:                .'</td>'
                   3115:                .&Apache::loncommon::end_data_table_row()
1.463     bisitz   3116:             );
1.461     neumanie 3117:         }
1.497     bisitz   3118: 
1.523     raeburn  3119:         $r->print(&Apache::loncommon::end_data_table().
                   3120:                   '<br style="line-height:2px;" />'.
                   3121:                   &Apache::loncommon::end_scrollbox());
1.209     www      3122:     }
                   3123: }
                   3124: 
1.563     damieng  3125: # Prints HTML to select the parameter level (resource, map/folder or course).
                   3126: # Used by table and overview modes.
                   3127: #
                   3128: # @param {Apache2::RequestRec} $r - the Apache request
                   3129: # @param {hash reference} $alllevs - all parameter levels, hash English title -> value
                   3130: # @param {string} $parmlev - selected level value (full|map|general), or ''
1.209     www      3131: sub levelmenu {
1.446     bisitz   3132:     my ($r,$alllevs,$parmlev)=@_;
                   3133: 
1.548     raeburn  3134:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parameter Level').
                   3135:                                                 &Apache::loncommon::help_open_topic('Course_Parameter_Levels')));
1.474     amueller 3136:     $r->print('<select id="parmlev" name="parmlev" onchange="showHide_courseContent()">');
1.548     raeburn  3137:     foreach my $lev (reverse(sort(keys(%{$alllevs})))) {
                   3138:         $r->print('<option value="'.$$alllevs{$lev}.'"');
                   3139:         if ($parmlev eq $$alllevs{$lev}) {
                   3140:             $r->print(' selected="selected"');
                   3141:         }
                   3142:         $r->print('>'.&mt($lev).'</option>');
1.208     www      3143:     }
1.446     bisitz   3144:     $r->print("</select>");
1.208     www      3145: }
                   3146: 
1.211     www      3147: 
1.563     damieng  3148: # Returns HTML to select a section (with a select HTML element).
                   3149: # Used by overview mode.
                   3150: #
                   3151: # @param {array reference} $selectedsections - list of selected section ids
                   3152: # @returns {string}
1.211     www      3153: sub sectionmenu {
1.553     raeburn  3154:     my ($selectedsections)=@_;
1.300     albertel 3155:     my %sectionhash = &Apache::loncommon::get_sections();
1.553     raeburn  3156:     return '' if (!%sectionhash);
1.300     albertel 3157: 
1.552     raeburn  3158:     my (@possibles,$disabled);
                   3159:     if ($env{'request.course.sec'} ne '') {
                   3160:         @possibles = ($env{'request.course.sec'});
                   3161:         $selectedsections = [$env{'request.course.sec'}];
                   3162:         $disabled = ' disabled="disabled"';
                   3163:     } else {
                   3164:         @possibles = ('all',sort(keys(%sectionhash)));
                   3165:     }
1.553     raeburn  3166:     my $output = '<select name="Section" multiple="multiple" size="8"'.$disabled.'>';
1.552     raeburn  3167:     foreach my $s (@possibles) {
1.553     raeburn  3168:         $output .= '    <option value="'.$s.'"';
                   3169:         if ((@{$selectedsections}) && (grep(/^\Q$s\E$/,@{$selectedsections}))) {  
                   3170:             $output .= ' selected="selected"';
1.473     amueller 3171:         }
1.553     raeburn  3172:         $output .= '>'."$s</option>\n";
1.300     albertel 3173:     }
1.553     raeburn  3174:     $output .= "</select>\n";
                   3175:     return $output;
1.269     raeburn  3176: }
                   3177: 
1.563     damieng  3178: # Returns HTML to select a group (with a select HTML element).
                   3179: # Used by overview mode.
                   3180: #
                   3181: # @param {array reference} $selectedgroups - list of selected group names
                   3182: # @returns {string}
1.269     raeburn  3183: sub groupmenu {
1.553     raeburn  3184:     my ($selectedgroups)=@_;
                   3185:     my %grouphash;
                   3186:     if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   3187:         %grouphash = &Apache::longroup::coursegroups();
                   3188:     } elsif ($env{'request.course.groups'} ne '') {
1.585     raeburn  3189:          map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'});
1.553     raeburn  3190:     }
                   3191:     return '' if (!%grouphash);
1.299     albertel 3192: 
1.553     raeburn  3193:     my $output = '<select name="Group" multiple="multiple" size="8">';
1.299     albertel 3194:     foreach my $group (sort(keys(%grouphash))) {
1.553     raeburn  3195:         $output .= '    <option value="'.$group.'"';
                   3196:         if ((@{$selectedgroups}) && (grep(/^\Q$group\E$/,\@{$selectedgroups}))) {
                   3197:             $output .=  ' selected="selected"';
1.473     amueller 3198:         }
1.553     raeburn  3199:         $output .= '>'."$group</option>\n";
1.211     www      3200:     }
1.553     raeburn  3201:     $output .= "</select>\n";
                   3202:     return $output;
1.211     www      3203: }
                   3204: 
1.563     damieng  3205: # Returns an array with the given parameter split by comma.
                   3206: # Used by assessparms (table mode).
                   3207: #
                   3208: # @param {string} $keyp - the string to split
                   3209: # @returns {Array<string>}
1.210     www      3210: sub keysplit {
                   3211:     my $keyp=shift;
                   3212:     return (split(/\,/,$keyp));
                   3213: }
                   3214: 
1.563     damieng  3215: # Returns the keys in $name, sorted using $keyorder.
                   3216: # Parameters are sorted by key, which means they are sorted by part first, then by name.
                   3217: # Used by assessparms (table mode) for resource level.
                   3218: #
                   3219: # @param {hash reference} $name - parameter key -> parameter name
                   3220: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3221: # @returns {Array<string>}
1.210     www      3222: sub keysinorder {
                   3223:     my ($name,$keyorder)=@_;
                   3224:     return sort {
1.560     damieng  3225:         $$keyorder{$a} <=> $$keyorder{$b};
1.548     raeburn  3226:     } (keys(%{$name}));
1.210     www      3227: }
                   3228: 
1.563     damieng  3229: # Returns the keys in $name, sorted using $keyorder to sort parameters by name first, then by part.
                   3230: # Used by assessparms (table mode) for map and general levels.
                   3231: #
                   3232: # @param {hash reference} $name - parameter key -> parameter name
                   3233: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3234: # @returns {Array<string>}
1.236     albertel 3235: sub keysinorder_bytype {
                   3236:     my ($name,$keyorder)=@_;
                   3237:     return sort {
1.563     damieng  3238:         my $ta=(split('_',$a))[-1]; # parameter name
1.560     damieng  3239:         my $tb=(split('_',$b))[-1];
                   3240:         if ($$keyorder{'parameter_0_'.$ta} == $$keyorder{'parameter_0_'.$tb}) {
                   3241:             return ($a cmp $b);
                   3242:         }
                   3243:         $$keyorder{'parameter_0_'.$ta} <=> $$keyorder{'parameter_0_'.$tb};
1.548     raeburn  3244:     } (keys(%{$name}));
1.236     albertel 3245: }
                   3246: 
1.563     damieng  3247: # Returns the keys in $name, sorted using $keyorder to sort parameters by name.
                   3248: # Used by defaultsetter (parameter settings default actions).
                   3249: #
                   3250: # @param {hash reference} $name - hash parameter name -> parameter title
                   3251: # @param {hash reference} $keyorder - hash parameter key -> appearance rank
                   3252: # @returns {Array<string>}
1.211     www      3253: sub keysindisplayorder {
                   3254:     my ($name,$keyorder)=@_;
                   3255:     return sort {
1.560     damieng  3256:         $$keyorder{'parameter_0_'.$a} <=> $$keyorder{'parameter_0_'.$b};
1.548     raeburn  3257:     } (keys(%{$name}));
1.211     www      3258: }
                   3259: 
1.563     damieng  3260: # Prints HTML with a choice to sort results by realm or student first.
                   3261: # Used by overview mode.
                   3262: #
                   3263: # @param {Apache2::RequestRec} $r - the Apache request
                   3264: # @param {string} $sortorder - realmstudent|studentrealm
1.608     raeburn  3265: # @param {string} $context - newoverview|overview
1.214     www      3266: sub sortmenu {
1.608     raeburn  3267:     my ($r,$sortorder,$context)=@_;
                   3268:     my %text;
                   3269:     if ($context eq 'newoverview') {
                   3270:         %text = &Apache::lonlocal::texthash (
                   3271:                    realmstudent => 'Sort by location in course first, then student (group/section)',
                   3272:                    studentrealm => 'Sort by student (group/section) first, then location in course',
                   3273:         );
                   3274:     } else {
                   3275:         %text = &Apache::lonlocal::texthash (
                   3276:                    realmstudent => 'Sort by realm first, then student (group/section)',
                   3277:                    studentrealm => 'Sort by student (group/section) first, then realm',
                   3278:         );
1.214     www      3279:     }
1.608     raeburn  3280:     my %sortchecked = (
                   3281:        realmstudent => ' checked="checked"',
                   3282:        studentrealm => '',
                   3283:     );
1.214     www      3284:     if ($sortorder eq 'studentrealm') {
1.608     raeburn  3285:         $sortchecked{'studentrealm'} = $sortchecked{'realmstudent'};
                   3286:         $sortchecked{'realmstudent'} = '';
                   3287:     }
                   3288:     foreach my $sorttype ('realmstudent','studentrealm') {
                   3289:         $r->print('<br /><label><input type="radio" name="sortorder" value="'.$sorttype.'"'.$sortchecked{$sorttype}.' />'.
                   3290:                   $text{$sorttype}.'</label>');
1.214     www      3291:     }
                   3292: }
                   3293: 
1.563     damieng  3294: # Returns a hash parameter key -> order (integer) giving the order for some parameters.
                   3295: #
                   3296: # @returns {hash}
1.211     www      3297: sub standardkeyorder {
                   3298:     return ('parameter_0_opendate' => 1,
1.473     amueller 3299:         'parameter_0_duedate' => 2,
                   3300:         'parameter_0_answerdate' => 3,
1.622   ! raeburn  3301:         'parameter_0_grace' => 4,
        !          3302:         'parameter_0_interval' => 5,
        !          3303:         'parameter_0_weight' => 6,
        !          3304:         'parameter_0_maxtries' => 7,
        !          3305:         'parameter_0_hinttries' => 8,
        !          3306:         'parameter_0_contentopen' => 9,
        !          3307:         'parameter_0_contentclose' => 10,
        !          3308:         'parameter_0_type' => 11,
        !          3309:         'parameter_0_problemstatus' => 12,
        !          3310:         'parameter_0_hiddenresource' => 13,
        !          3311:         'parameter_0_hiddenparts' => 14,
        !          3312:         'parameter_0_display' => 15,
        !          3313:         'parameter_0_ordered' => 16,
        !          3314:         'parameter_0_tol' => 17,
        !          3315:         'parameter_0_sig' => 18,
        !          3316:         'parameter_0_turnoffunit' => 19,
        !          3317:         'parameter_0_discussend' => 20,
        !          3318:         'parameter_0_discusshide' => 21,
        !          3319:         'parameter_0_discussvote' => 22,
        !          3320:         'parameter_0_printstartdate' => 23,
        !          3321:         'parameter_0_printenddate' => 24);
1.211     www      3322: }
                   3323: 
1.59      matthew  3324: 
1.560     damieng  3325: # Table mode UI.
1.563     damieng  3326: # If nothing is selected, prints HTML forms to select resources, parts, parameters, user, group and section.
                   3327: # Otherwise, prints the parameter table, with a link to change the selection unless a single resource is selected.
                   3328: #
                   3329: # Parameters used from the request:
                   3330: # action - handler action (see handler), usermenu is checking for value 'settable'
                   3331: # cgroup - selected group
                   3332: # command - 'set': direct access to table mode for a resource
                   3333: # csec - selected section
                   3334: # dis - set when the "Update Display" button was used, used only to discard command 'set'
                   3335: # hideparmsel - can be 'hidden' to hide the parameter selection div initially and display the "Change Parameter Selection" link instead (which displays the div)
                   3336: # id - student/employee ID
                   3337: # parmlev - selected level (full|map|general)
                   3338: # part - selected part (unused ?)
                   3339: # pres_marker - &&&-separated parameter identifiers, "resource id&part_parameter name&level"
                   3340: # pres_type - &&&-separated parameter types
                   3341: # pres_value - &&&-separated parameter values
                   3342: # prevvisit - '1' if the user has submitted the form before
                   3343: # pscat (multiple values) - selected parameter names
1.566     damieng  3344: # pschp - selected map pc, or 'all'
1.563     damieng  3345: # psprt (multiple values) - list of selected parameter parts
                   3346: # filter - part of or whole parameter name, to be filtered out when parameters are displayed (unused ?)
                   3347: # recent_* (* = parameter type) - recent values entered by the user for parameter types
                   3348: # symb - resource symb (when a single resource is selected)
                   3349: # udom - selected user domain
                   3350: # uname - selected user name
                   3351: # url - used only with command 'set', the resource url
                   3352: #
                   3353: # @param {Apache2::RequestRec} $r - the Apache request
1.568     raeburn  3354: # @param $parm_permission - ref to hash of permissions
                   3355: #                           if $parm_permission->{'edit'} is true, editing is allowed.
1.30      www      3356: sub assessparms {
1.1       www      3357: 
1.568     raeburn  3358:     my ($r,$parm_permission) = @_;
1.201     www      3359: 
1.512     foxr     3360: 
                   3361: # -------------------------------------------------------- Variable declaration
1.566     damieng  3362:     my @ids=(); # resource and map ids
                   3363:     my %symbp=(); # hash map pc or resource/map id -> map src.'___(all)' or resource symb
                   3364:     my %mapp=(); # hash map pc or resource/map id -> enclosing map src
                   3365:     my %typep=(); # hash resource/map id -> resource type (file extension)
                   3366:     my %keyp=(); # hash resource/map id -> comma-separated list of parameter keys
                   3367:     my %uris=(); # hash resource/map id -> resource src
                   3368:     my %maptitles=(); # hash map pc or src -> map title
                   3369:     my %allmaps=(); # hash map pc -> map src
1.582     raeburn  3370:     my %allmaps_inverted=(); # hash map src -> map pc
1.563     damieng  3371:     my %alllevs=(); # hash English level title -> value
                   3372: 
                   3373:     my $uname; # selected user name
                   3374:     my $udom; # selected user domain
                   3375:     my $uhome; # server with the user's files, or 'no_host'
                   3376:     my $csec; # selected section name
                   3377:     my $cgroup; # selected group name
                   3378:     my @usersgroups = (); # list of the user groups
1.582     raeburn  3379:     my $numreclinks = 0;
1.446     bisitz   3380: 
1.190     albertel 3381:     my $coursename=$env{'course.'.$env{'request.course.id'}.'.description'};
1.187     www      3382: 
1.57      albertel 3383:     $alllevs{'Resource Level'}='full';
1.215     www      3384:     $alllevs{'Map/Folder Level'}='map';
1.57      albertel 3385:     $alllevs{'Course Level'}='general';
                   3386: 
1.563     damieng  3387:     my %allparms; # hash parameter name -> parameter title
                   3388:     my %allparts; # hash parameter part -> part title
1.512     foxr     3389: # ------------------------------------------------------------------------------
                   3390: 
1.210     www      3391: #
                   3392: # Order in which these parameters will be displayed
                   3393: #
1.211     www      3394:     my %keyorder=&standardkeyorder();
                   3395: 
1.512     foxr     3396: #    @ids=();
                   3397: #    %symbp=();       # These seem defined above already.
                   3398: #    %typep=();
1.43      albertel 3399: 
                   3400:     my $message='';
                   3401: 
1.190     albertel 3402:     $csec=$env{'form.csec'};
1.552     raeburn  3403:     if ($env{'request.course.sec'} ne '') {
                   3404:         $csec = $env{'request.course.sec'};    
                   3405:     }
                   3406: 
1.553     raeburn  3407: # Check group privs.
1.269     raeburn  3408:     $cgroup=$env{'form.cgroup'};
1.553     raeburn  3409:     my $noeditgrp; 
                   3410:     if ($cgroup ne '') {
                   3411:         unless (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   3412:             if (($env{'request.course.groups'} eq '') || 
1.585     raeburn  3413:                 (!grep(/^\Q$cgroup\E$/,split(/:/,$env{'request.course.groups'})))) {
1.553     raeburn  3414:                 $noeditgrp = 1;
                   3415:             }
                   3416:         }
                   3417:     }
1.188     www      3418: 
1.190     albertel 3419:     if      ($udom=$env{'form.udom'}) {
                   3420:     } elsif ($udom=$env{'request.role.domain'}) {
                   3421:     } elsif ($udom=$env{'user.domain'}) {
1.172     albertel 3422:     } else {
1.473     amueller 3423:         $udom=$r->dir_config('lonDefDomain');
1.172     albertel 3424:     }
1.468     amueller 3425:     
1.43      albertel 3426: 
1.134     albertel 3427:     my @pscat=&Apache::loncommon::get_env_multiple('form.pscat');
1.190     albertel 3428:     my $pschp=$env{'form.pschp'};
1.506     www      3429: 
                   3430: 
1.134     albertel 3431:     my @psprt=&Apache::loncommon::get_env_multiple('form.psprt');
1.516     www      3432:     if (!@psprt) { $psprt[0]='all'; }
1.506     www      3433:     if (($env{'form.part'}) && ($psprt[0] ne 'all')) { $psprt[0]=$env{'form.part'}; }
1.57      albertel 3434: 
1.43      albertel 3435:     my $pssymb='';
1.57      albertel 3436:     my $parmlev='';
1.446     bisitz   3437: 
1.190     albertel 3438:     unless ($env{'form.parmlev'}) {
1.57      albertel 3439:         $parmlev = 'map';
                   3440:     } else {
1.190     albertel 3441:         $parmlev = $env{'form.parmlev'};
1.57      albertel 3442:     }
1.26      www      3443: 
1.29      www      3444: # ----------------------------------------------- Was this started from grades?
                   3445: 
1.560     damieng  3446:     if (($env{'form.command'} eq 'set') && ($env{'form.url'}) &&
                   3447:             (!$env{'form.dis'})) {
1.473     amueller 3448:         my $url=$env{'form.url'};
                   3449:         $url=~s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
                   3450:         $pssymb=&Apache::lonnet::symbread($url);
                   3451:         if (!@pscat) { @pscat=('all'); }
                   3452:         $pschp='';
1.57      albertel 3453:         $parmlev = 'full';
1.190     albertel 3454:     } elsif ($env{'form.symb'}) {
1.473     amueller 3455:         $pssymb=$env{'form.symb'};
                   3456:         if (!@pscat) { @pscat=('all'); }
                   3457:         $pschp='';
1.57      albertel 3458:         $parmlev = 'full';
1.43      albertel 3459:     } else {
1.473     amueller 3460:         $env{'form.url'}='';
1.43      albertel 3461:     }
                   3462: 
1.190     albertel 3463:     my $id=$env{'form.id'};
1.43      albertel 3464:     if (($id) && ($udom)) {
1.555     raeburn  3465:         $uname=(&Apache::lonnet::idget($udom,[$id],'ids'))[1];
1.473     amueller 3466:         if ($uname) {
                   3467:             $id='';
                   3468:         } else {
                   3469:             $message=
1.540     bisitz   3470:                 '<p class="LC_warning">'.
                   3471:                 &mt('Unknown ID [_1] at domain [_2]',
                   3472:                     "'".$id."'","'".$udom."'").
                   3473:                 '</p>';
1.473     amueller 3474:         }
1.43      albertel 3475:     } else {
1.473     amueller 3476:         $uname=$env{'form.uname'};
1.43      albertel 3477:     }
                   3478:     unless ($udom) { $uname=''; }
                   3479:     $uhome='';
                   3480:     if ($uname) {
1.473     amueller 3481:         $uhome=&Apache::lonnet::homeserver($uname,$udom);
1.43      albertel 3482:         if ($uhome eq 'no_host') {
1.473     amueller 3483:             $message=
1.540     bisitz   3484:                 '<p class="LC_warning">'.
                   3485:                 &mt('Unknown user [_1] at domain [_2]',
                   3486:                     "'".$uname."'","'".$udom."'").
                   3487:                 '</p>';
1.473     amueller 3488:             $uname='';
1.12      www      3489:         } else {
1.473     amueller 3490:             $csec=&Apache::lonnet::getsection($udom,$uname,
                   3491:                           $env{'request.course.id'});
                   3492:             if ($csec eq '-1') {
1.596     raeburn  3493:                 my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   3494:                 if ($env{'form.userroles'} eq 'any') {
                   3495:                     if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) {
                   3496:                         $csec = $env{'request.course.sec'};
                   3497:                         $message = '<span class="LC_info">';
                   3498:                         if ($crstype eq 'Community') {
                   3499:                             $message .= &mt('User [_1] at domain [_2] has a non-member role in this community',
                   3500:                                             $uname,$udom);
                   3501:                         } else {
                   3502:                             $message .= &mt('User [_1] at domain [_2] has a non-student role in this course',
                   3503:                                             $uname,$udom);
                   3504:                         }
                   3505:                         $message .= '</span>';
                   3506:                     } else {
                   3507:                         my @possroles = ('in','ep','ta','cr');
                   3508:                         if ($crstype eq 'Community') {
                   3509:                             unshift(@possroles,'co');
                   3510:                         } else {
                   3511:                             unshift(@possroles,'cc');
                   3512:                         }
                   3513:                         my %not_student_roles =
                   3514:                             &Apache::lonnet::get_my_roles($uname,$udom,'userroles',['active'],
                   3515:                                                           \@possroles,[$udom],1,1);
                   3516:                         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   3517:                         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   3518:                         my %sections_by_role;
                   3519:                         foreach my $role (keys(%not_student_roles)) {
                   3520:                             if ($role =~ /^\Q$cnum:$cdom:\E([^:]+):(|[^:]+)$/) {
                   3521:                                 my ($rolename,$sec) = ($1,$2);
                   3522:                                 if ($rolename =~ m{^cr/}) {
                   3523:                                     $rolename = 'cr';
                   3524:                                 }
                   3525:                                 push(@{$sections_by_role{$rolename}},$sec);
                   3526:                             }
                   3527:                         }
                   3528:                         my $numroles = scalar(keys(%sections_by_role));
                   3529:                         if ($numroles) {
                   3530:                             foreach my $role (@possroles) {
                   3531:                                 if (ref($sections_by_role{$role}) eq 'ARRAY') {
                   3532:                                     my @secs = sort { $a <=> $b } @{$sections_by_role{$role}};
                   3533:                                     $csec = $secs[0];
                   3534:                                     last;
                   3535:                                 }
                   3536:                             }
                   3537:                         }
                   3538:                         if ($csec eq '-1') {
                   3539:                             $message = '<span class="LC_warning">';
                   3540:                             if ($crstype eq 'Community') {
                   3541:                                 $message .= &mt('User [_1] at domain [_2] does not have a role in this community',
                   3542:                                                 $uname,$udom);
                   3543:                             } else {
                   3544:                                 $message .= &mt('User [_1] at domain [_2] does not have a role in this course',
                   3545:                                                 $uname,$udom);
                   3546:                             }
                   3547:                             $message .= '</span>';
                   3548:                             $uname='';
                   3549:                             if ($env{'request.course.sec'} ne '') {
                   3550:                                 $csec=$env{'request.course.sec'};
                   3551:                             } else {
                   3552:                                 $csec=$env{'form.csec'};
                   3553:                             }
                   3554:                             $cgroup=$env{'form.cgroup'};
                   3555:                         } else {
                   3556:                             $message = '<span class="LC_info">';
                   3557:                             if ($crstype eq 'Community') {
                   3558:                                 $message .= &mt('User [_1] at domain [_2] has a non-member role in this community',
                   3559:                                          $uname,$udom);
                   3560:                             } else {
                   3561:                                 $message .= &mt('User [_1] at domain [_2] has a non-student role in this course',
                   3562:                                                 $uname,$udom);
                   3563:                             }
                   3564:                             $message .= '</span>';
                   3565:                         }
                   3566:                     }
1.594     raeburn  3567:                 } else {
1.596     raeburn  3568:                     $message = '<span class="LC_warning">';
                   3569:                     if ($crstype eq 'Community') {
                   3570:                         $message .= &mt('User [_1] at domain [_2] does not have a member role in this community',
                   3571:                                          $uname,$udom);
                   3572:                     } else {
                   3573:                          $message .= &mt('User [_1] at domain [_2] does not have a student role in this course',
                   3574:                                          $uname,$udom);
                   3575:                     }
                   3576:                     $message .= '</span>';
                   3577:                     $uname='';
                   3578:                     if ($env{'request.course.sec'} ne '') {
                   3579:                         $csec=$env{'request.course.sec'};
                   3580:                     } else {
                   3581:                         $csec=$env{'form.csec'};
                   3582:                     }
                   3583:                     $cgroup=$env{'form.cgroup'};
1.594     raeburn  3584:                 }
                   3585:             } elsif ($env{'request.course.sec'} ne '') {
                   3586:                 if ($csec ne $env{'request.course.sec'}) {
1.596     raeburn  3587:                     $message='<span class="LC_warning">'.
1.594     raeburn  3588:                               &mt("User '[_1]' at domain '[_2]' not in section '[_3]'",
                   3589:                                   $uname,$udom,$env{'request.course.sec'}).
                   3590:                               '</span>';
                   3591:                     $uname='';
                   3592:                     $csec=$env{'request.course.sec'};
                   3593:                 }
1.269     raeburn  3594:                 $cgroup=$env{'form.cgroup'};
1.596     raeburn  3595:             }
                   3596:             if ($uname ne '') {
1.473     amueller 3597:                 my %name=&Apache::lonnet::userenvironment($udom,$uname,
                   3598:                   ('firstname','middlename','lastname','generation','id'));
1.596     raeburn  3599:                 $message .= "\n<p>\n".&mt('Full Name').': '
                   3600:                             .$name{'firstname'}.' '.$name{'middlename'}.' '
                   3601:                             .$name{'lastname'}.' '.$name{'generation'}
                   3602:                             ."<br />\n".&mt('Student/Employee ID').': '.$name{'id'}.'</p>';
                   3603:                 @usersgroups = &Apache::lonnet::get_users_groups(
                   3604:                                    $udom,$uname,$env{'request.course.id'});
                   3605:                 if (@usersgroups > 0) {
                   3606:                     unless (grep(/^\Q$cgroup\E$/,@usersgroups)) {
                   3607:                         $cgroup = $usersgroups[0];
                   3608:                     }
                   3609:                 } else {
                   3610:                     $cgroup = '';
1.297     raeburn  3611:                 }
1.269     raeburn  3612:             }
1.12      www      3613:         }
1.43      albertel 3614:     }
1.2       www      3615: 
1.43      albertel 3616:     unless ($csec) { $csec=''; }
1.269     raeburn  3617:     unless ($cgroup) { $cgroup=''; }
1.12      www      3618: 
1.14      www      3619: # --------------------------------------------------------- Get all assessments
1.446     bisitz   3620:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 3621:                 \%mapp, \%symbp,\%maptitles,\%uris,
1.603     raeburn  3622:                 \%keyorder,undef,$pssymb);
1.63      bowersj2 3623: 
1.582     raeburn  3624:     %allmaps_inverted = reverse(%allmaps);
                   3625: 
1.57      albertel 3626:     $mapp{'0.0'} = '';
                   3627:     $symbp{'0.0'} = '';
1.99      albertel 3628: 
1.14      www      3629: # ---------------------------------------------------------- Anything to store?
1.568     raeburn  3630:     if ($env{'form.pres_marker'} && $parm_permission->{'edit'}) {
1.205     www      3631:         my @markers=split(/\&\&\&/,$env{'form.pres_marker'});
                   3632:         my @values=split(/\&\&\&/,$env{'form.pres_value'});
                   3633:         my @types=split(/\&\&\&/,$env{'form.pres_type'});
1.500     raeburn  3634:         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   3635:         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.504     raeburn  3636:         my $chome = $env{'course.'.$env{'request.course.id'}.'.home'};
                   3637:         my ($got_chostname,$chostname,$cmajor,$cminor);
                   3638:         my $totalstored = 0;
1.605     raeburn  3639:         my $totalskippeduser = 0;
1.546     raeburn  3640:         my $now = time;
1.473     amueller 3641:         for (my $i=0;$i<=$#markers;$i++) {
1.557     raeburn  3642:             my ($needsrelease,$needsnewer,$name,$namematch);
1.556     raeburn  3643:             if (($env{'request.course.sec'} ne '') && ($markers[$i] =~ /\&(9|10|11|12)$/)) {
1.552     raeburn  3644:                 next if ($csec ne $env{'request.course.sec'});
                   3645:             }
1.556     raeburn  3646:             if ($markers[$i] =~ /\&(8|7|6|5)$/) {
1.553     raeburn  3647:                 next if ($noeditgrp);
1.605     raeburn  3648:             } elsif ($markers[$i] =~ /\&(4|3|2|1)$/) {
                   3649:                 if ($uname eq '') {
                   3650:                     $totalskippeduser ++;
                   3651:                     next;
                   3652:                 }
1.557     raeburn  3653:             }
                   3654:             if ($markers[$i] =~ /\&(17|11|7|3)$/) {
                   3655:                 $namematch = 'maplevelrecurse';
                   3656:             }
1.556     raeburn  3657:             if ($markers[$i] =~ /^[\d.]+\&0_availablestudent\&(1|2|3|4)$/) {
1.437     raeburn  3658:                 my (@ok_slots,@fail_slots,@del_slots);
                   3659:                 my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
                   3660:                 my ($level,@all) =
                   3661:                     &parmval_by_symb('0.availablestudent',$pssymb,'',$uname,$udom,
                   3662:                                      $csec,$cgroup,$courseopt);
                   3663:                 foreach my $slot_name (split(/:/,$values[$i])) {
                   3664:                     next if ($slot_name eq '');
                   3665:                     if (&update_slots($slot_name,$cdom,$cnum,$pssymb,$uname,$udom) eq 'ok') {
                   3666:                         push(@ok_slots,$slot_name);
                   3667: 
                   3668:                     } else {
                   3669:                         push(@fail_slots,$slot_name);
                   3670:                     }
                   3671:                 }
                   3672:                 if (@ok_slots) {
                   3673:                     $values[$i] = join(':',@ok_slots);
                   3674:                 } else {
                   3675:                     $values[$i] = '';
                   3676:                 }
                   3677:                 if ($all[$level] ne '') {
                   3678:                     my @existing = split(/:/,$all[$level]);
                   3679:                     foreach my $slot_name (@existing) {
                   3680:                         if (!grep(/^\Q$slot_name\E$/,split(/:/,$values[$i]))) {
                   3681:                             if (&delete_slots($slot_name,$cdom,$cnum,$uname,$udom,$pssymb) eq 'ok') {
                   3682:                                 push(@del_slots,$slot_name);
                   3683:                             }
                   3684:                         }
                   3685:                     }
                   3686:                 }
1.554     raeburn  3687:             } elsif ($markers[$i] =~ /_(type|lenient|retrypartial|discussvote|examcode|printstartdate|printenddate|acc|interval)\&\d+$/) {
1.514     raeburn  3688:                 $name = $1;
1.533     raeburn  3689:                 my $val = $values[$i];
1.549     raeburn  3690:                 my $valmatch = '';
1.533     raeburn  3691:                 if ($name eq 'examcode') {
1.544     raeburn  3692:                     if (&Apache::lonnet::validCODE($values[$i])) {
                   3693:                         $val = 'valid';
                   3694:                     }
1.546     raeburn  3695:                 } elsif ($name eq 'printstartdate') {
                   3696:                     if ($val =~ /^\d+$/) {
                   3697:                         if ($val > $now) {
                   3698:                             $val = 'future';
                   3699:                         }
                   3700:                     } 
                   3701:                 } elsif ($name eq 'printenddate') {
                   3702:                     if ($val =~ /^\d+$/) {
                   3703:                         if ($val < $now) {
                   3704:                             $val = 'past';
                   3705:                         }
                   3706:                     }
1.549     raeburn  3707:                 } elsif (($name eq 'lenient') || ($name eq 'acc')) {
                   3708:                     my $stringtype = &get_stringtype($name);
                   3709:                     my $stringmatch = &standard_string_matches($stringtype);
                   3710:                     if (ref($stringmatch) eq 'ARRAY') {
                   3711:                         foreach my $item (@{$stringmatch}) {
                   3712:                             if (ref($item) eq 'ARRAY') {
                   3713:                                 my ($regexpname,$pattern) = @{$item};
                   3714:                                 if ($pattern ne '') {
                   3715:                                     if ($val =~ /$pattern/) {
                   3716:                                         $valmatch = $regexpname;
                   3717:                                         $val = '';
                   3718:                                         last;
                   3719:                                     }
                   3720:                                 }
                   3721:                             }
                   3722:                         }
                   3723:                     }
1.554     raeburn  3724:                 } elsif ($name eq 'interval') {
                   3725:                     my $intervaltype = &get_intervaltype($name);
                   3726:                     my $intervalmatch = &standard_interval_matches($intervaltype);
                   3727:                     if (ref($intervalmatch) eq 'ARRAY') {
                   3728:                         foreach my $item (@{$intervalmatch}) {
                   3729:                             if (ref($item) eq 'ARRAY') {
                   3730:                                 my ($regexpname,$pattern) = @{$item};
                   3731:                                 if ($pattern ne '') {
                   3732:                                     if ($val =~ /$pattern/) {
                   3733:                                         $valmatch = $regexpname;
                   3734:                                         $val = '';
                   3735:                                         last;
                   3736:                                     }
                   3737:                                 }
                   3738:                             }
                   3739:                         }
                   3740:                     }
1.533     raeburn  3741:                 }
1.504     raeburn  3742:                 $needsrelease =
1.557     raeburn  3743:                     $Apache::lonnet::needsrelease{"parameter:$name:$val:$valmatch:"};
1.504     raeburn  3744:                 if ($needsrelease) {
1.505     raeburn  3745:                     unless ($got_chostname) {
1.514     raeburn  3746:                         ($chostname,$cmajor,$cminor) = &parameter_release_vars();
1.504     raeburn  3747:                         $got_chostname = 1;
1.546     raeburn  3748:                     } 
1.557     raeburn  3749:                     $needsnewer = &parameter_releasecheck($name,$val,$valmatch,undef,
1.514     raeburn  3750:                                                           $needsrelease,
                   3751:                                                           $cmajor,$cminor);
1.500     raeburn  3752:                 }
1.437     raeburn  3753:             }
1.504     raeburn  3754:             if ($needsnewer) {
1.557     raeburn  3755:                 undef($namematch);
                   3756:             } else {
                   3757:                 my $currneeded;
                   3758:                 if ($needsrelease) {
                   3759:                     $currneeded = $needsrelease;
                   3760:                 }
                   3761:                 if ($namematch) {
                   3762:                     $needsrelease =
                   3763:                         $Apache::lonnet::needsrelease{"parameter::::$namematch"};
                   3764:                     if (($needsrelease) && (($currneeded eq '') || ($needsrelease < $currneeded))) {
                   3765:                         unless ($got_chostname) {
                   3766:                             ($chostname,$cmajor,$cminor) = &parameter_release_vars();
                   3767:                             $got_chostname = 1;
                   3768:                         }
                   3769:                         $needsnewer = &parameter_releasecheck(undef,undef,undef,$namematch,
                   3770:                                                               $needsrelease,
                   3771:                                                               $cmajor,$cminor);
                   3772:                     } else {
                   3773:                         undef($namematch);
                   3774:                     }
                   3775:                 }
                   3776:             }
                   3777:             if ($needsnewer) {
                   3778:                 $message .= &oldversion_warning($name,$namematch,$values[$i],$chostname,$cmajor,
1.504     raeburn  3779:                                                 $cminor,$needsrelease);
                   3780:             } else {
                   3781:                 $message.=&storeparm(split(/\&/,$markers[$i]),
                   3782:                                      $values[$i],
                   3783:                                      $types[$i],
                   3784:                                      $uname,$udom,$csec,$cgroup);
                   3785:                 $totalstored ++;
                   3786:             }
1.473     amueller 3787:         }
1.68      www      3788: # ---------------------------------------------------------------- Done storing
1.504     raeburn  3789:         if ($totalstored) {
                   3790:             $message.='<p class="LC_warning">'
1.605     raeburn  3791:                      .&mt('Changes for [quant,_1,parameter] saved.',$totalstored)
                   3792:                      .'<br />'
1.504     raeburn  3793:                      .&mt('Changes can take up to 10 minutes before being active for all students.')
                   3794:                      .&Apache::loncommon::help_open_topic('Caching')
                   3795:                      .'</p>';
1.605     raeburn  3796:         } else {
                   3797:             $message.='<p class="LC_info">'.&mt('No parameter changes saved.').'</p>';
                   3798:         }
                   3799:         if ($totalskippeduser) {
                   3800:             $message .= '<p class="LC_warning">';
                   3801:             if ($uhome eq 'no_host') {
                   3802:                 $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the username or ID was invalid.',
                   3803:                                 $totalskippeduser);
                   3804:             } elsif ($env{'form.userroles'} eq 'any') {
                   3805:                 $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user does not have a course role.',
                   3806:                                 $totalskippeduser);
                   3807:             } else {
                   3808:                 $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user is not a student.',
                   3809:                                 $totalskippeduser);
                   3810:             }
                   3811:             $message .= '</p>';
1.504     raeburn  3812:         }
1.68      www      3813:     }
1.584     raeburn  3814: 
1.57      albertel 3815: #----------------------------------------------- if all selected, fill in array
1.563     damieng  3816:     if ($pscat[0] eq "all") {
                   3817:         @pscat = (keys(%allparms));
                   3818:     }
                   3819:     if (!@pscat) {
                   3820:         @pscat=('duedate','opendate','answerdate','weight','maxtries','type','problemstatus')
                   3821:     };
                   3822:     if ($psprt[0] eq "all" || !@psprt) {
                   3823:         @psprt = (keys(%allparts));
                   3824:     }
1.2       www      3825: # ------------------------------------------------------------------ Start page
1.63      bowersj2 3826: 
1.531     raeburn  3827:     my $crstype = &Apache::loncommon::course_type();
                   3828:     &startpage($r,$pssymb,$crstype);
1.57      albertel 3829: 
1.548     raeburn  3830:     foreach my $item ('tolerance','date_default','date_start','date_end',
1.589     raeburn  3831:             'date_interval','int','float','string','string_lenient',
                   3832:             'string_examcode','string_deeplink','string_discussvote',
                   3833:             'string_useslots','string_problemstatus','string_ip',
1.622   ! raeburn  3834:             'string_questiontype','string_tex','string_grace') {
1.473     amueller 3835:         $r->print('<input type="hidden" value="'.
1.563     damieng  3836:             &HTML::Entities::encode($env{'form.recent_'.$item},'"&<>').
                   3837:             '" name="recent_'.$item.'" />');
1.44      albertel 3838:     }
1.446     bisitz   3839: 
1.459     bisitz   3840:     # ----- Start Parameter Selection
                   3841: 
1.606     raeburn  3842:     # Hide parm selection and possibly table?
                   3843:     my ($tablejs,$tabledivsty);
                   3844:     if (((($env{'form.uname'} ne '') || ($env{'form.id'} ne '')) && ($uname eq '')) &&
                   3845:         ($env{'form.dis'}) && ($pssymb eq '')) {
                   3846:         $tablejs = 'document.getElementById('."'parmtable'".').style.display = "";';
                   3847:         $tabledivsty = ' style="display:none"';
                   3848:     }
1.459     bisitz   3849:     $r->print(<<ENDPARMSELSCRIPT);
                   3850: <script type="text/javascript">
                   3851: // <![CDATA[
                   3852: function parmsel_show() {
1.562     damieng  3853:     document.getElementById('parmsel').style.display = "";
                   3854:     document.getElementById('parmsellink').style.display = "none";
1.606     raeburn  3855:     $tablejs
1.459     bisitz   3856: }
                   3857: // ]]>
                   3858: </script>
                   3859: ENDPARMSELSCRIPT
1.474     amueller 3860:     
1.445     neumanie 3861:     if (!$pssymb) {
1.563     damieng  3862:         # No single resource selected, print forms to select things (hidden after first selection)
1.486     www      3863:         my $parmselhiddenstyle=' style="display:none"';
                   3864:         if($env{'form.hideparmsel'} eq 'hidden') {
                   3865:            $r->print('<div id="parmsel"'.$parmselhiddenstyle.'>');
                   3866:         } else  {
                   3867:            $r->print('<div id="parmsel">');
                   3868:         }
                   3869: 
1.491     bisitz   3870:         # Step 1
1.523     raeburn  3871:         $r->print(&Apache::lonhtmlcommon::topic_bar(1,&mt('Resource Specification'),'parmstep1'));
                   3872:         $r->print('
1.474     amueller 3873: <script type="text/javascript">
1.523     raeburn  3874: // <![CDATA['.
                   3875:                  &showhide_js().'
1.474     amueller 3876: // ]]>
                   3877: </script>
1.523     raeburn  3878: ');
                   3879:         $r->print(&Apache::lonhtmlcommon::start_pick_box(undef,'parmlevel'));
1.209     www      3880:         &levelmenu($r,\%alllevs,$parmlev);
1.491     bisitz   3881:         $r->print(&Apache::lonhtmlcommon::row_closure());
1.610     raeburn  3882:         &mapmenu($r,\%allmaps,$pschp,\%maptitles,\%symbp,$parmlev);
1.491     bisitz   3883:         $r->print(&Apache::lonhtmlcommon::row_closure());
                   3884:         $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parts to View')));
                   3885:         &partmenu($r,\%allparts,\@psprt);
1.474     amueller 3886:         $r->print(&Apache::lonhtmlcommon::row_closure(1));
                   3887:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.491     bisitz   3888: 
                   3889:         # Step 2
1.523     raeburn  3890:         $r->print(&Apache::lonhtmlcommon::topic_bar(2,&mt('Parameter Specification'),'parmstep2'));
1.581     raeburn  3891:         &displaymenu($r,\%allparms,\@pscat,\%keyorder,'parmmenuscroll');
1.491     bisitz   3892: 
                   3893:         # Step 3
1.523     raeburn  3894:         $r->print(&Apache::lonhtmlcommon::topic_bar(3,&mt('User Specification (optional)'),'parmstep3'));
1.486     www      3895:         $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.553     raeburn  3896:         &usermenu($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,\@usersgroups,$pssymb);
1.486     www      3897:         $r->print(&Apache::lonhtmlcommon::row_closure(1));
                   3898:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
1.491     bisitz   3899: 
                   3900:         # Update Display Button
1.486     www      3901:         $r->print('<p>'
                   3902:              .'<input type="submit" name="dis"'
1.511     www      3903:              .' value="'.&mt('Update Display').'" />'
1.486     www      3904:              .'<input type="hidden" name="hideparmsel" value="hidden" />'
                   3905:              .'</p>');
                   3906:         $r->print('</div>');
1.491     bisitz   3907: 
1.486     www      3908:         # Offer link to display parameter selection again
                   3909:         $r->print('<p id="parmsellink"');
                   3910:         if ($env{'form.hideparmsel'} ne 'hidden') {
                   3911:            $r->print($parmselhiddenstyle);
                   3912:         }
                   3913:         $r->print('>'
                   3914:              .'<a href="javascript:parmsel_show()">'
                   3915:              .&mt('Change Parameter Selection')
                   3916:              .'</a>'
                   3917:              .'</p>');
1.44      albertel 3918:     } else {
1.478     amueller 3919:         # parameter screen for a single resource. 
1.486     www      3920:         my ($map,$iid,$resource)=&Apache::lonnet::decode_symb($pssymb);
1.473     amueller 3921:         my $title = &Apache::lonnet::gettitle($pssymb);
1.501     bisitz   3922:         $r->print(&mt('Specific Resource: [_1] ([_2])',
                   3923:                          $title,'<span class="LC_filename">'.$resource.'</span>').
1.472     amueller 3924:                 '<input type="hidden" value="'.$pssymb.'" name="symb" />'.
1.486     www      3925:                   '<br />');
                   3926:         $r->print(&Apache::lonhtmlcommon::topic_bar('',&mt('Additional Display Specification (optional)')));
                   3927:         $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.553     raeburn  3928:         &usermenu($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,\@usersgroups,$pssymb);
1.486     www      3929:         $r->print(&Apache::lonhtmlcommon::row_closure(1));
                   3930:         $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   3931:         $r->print('<p>'
1.459     bisitz   3932:              .'<input type="submit" name="dis"'
1.511     www      3933:              .' value="'.&mt('Update Display').'" />'
1.459     bisitz   3934:              .'<input type="hidden" name="hideparmsel" value="hidden" />'
1.486     www      3935:              .'</p>');
1.459     bisitz   3936:     }
1.478     amueller 3937:     
1.486     www      3938:     # ----- End Parameter Selection
1.57      albertel 3939: 
1.459     bisitz   3940:     # Display Messages
                   3941:     $r->print('<div>'.$message.'</div>');
1.210     www      3942: 
1.57      albertel 3943: 
                   3944:     my @temp_pscat;
                   3945:     map {
                   3946:         my $cat = $_;
                   3947:         push(@temp_pscat, map { $_.'.'.$cat } @psprt);
                   3948:     } @pscat;
                   3949: 
                   3950:     @pscat = @temp_pscat;
                   3951: 
1.548     raeburn  3952: 
1.209     www      3953:     if (($env{'form.prevvisit'}) || ($pschp) || ($pssymb)) {
1.10      www      3954: # ----------------------------------------------------------------- Start Table
1.57      albertel 3955:         my @catmarker=map { tr|.|_|; 'parameter_'.$_; } @pscat;
1.190     albertel 3956:         my $csuname=$env{'user.name'};
                   3957:         my $csudom=$env{'user.domain'};
1.568     raeburn  3958:         my $readonly = 1;
                   3959:         if ($parm_permission->{'edit'}) {
                   3960:             undef($readonly); 
                   3961:         }
1.606     raeburn  3962:         $r->print('<div id="parmtable"'.$tabledivsty.'>');
1.57      albertel 3963: 
1.203     www      3964:         if ($parmlev eq 'full') {
1.506     www      3965: #
                   3966: # This produces the cascading table output of parameters
                   3967: #
1.578     raeburn  3968:             my $coursespan=$csec?8:5;
                   3969:             my $userspan=3;
1.560     damieng  3970:             if ($cgroup ne '') {
1.578     raeburn  3971:                 $coursespan += 3;
1.560     damieng  3972:             }
1.473     amueller 3973: 
1.560     damieng  3974:             $r->print(&Apache::loncommon::start_data_table());
                   3975:             #
                   3976:             # This produces the headers
                   3977:             #
                   3978:             $r->print('<tr><td colspan="5"></td>');
                   3979:             $r->print('<th colspan="'.($coursespan).'">'.&mt('Any User').'</th>');
                   3980:             if ($uname) {
1.473     amueller 3981:                 if (@usersgroups > 1) {
1.560     damieng  3982:                     $userspan ++;
                   3983:                 }
                   3984:                 $r->print('<th colspan="'.$userspan.'" rowspan="2">');
                   3985:                 $r->print(&mt('User [_1] at Domain [_2]',"'".$uname."'","'".$udom."'").'</th>');
                   3986:             }
                   3987:             my %lt=&Apache::lonlocal::texthash(
1.473     amueller 3988:                 'pie'    => "Parameter in Effect",
                   3989:                 'csv'    => "Current Session Value",
1.472     amueller 3990:                 'rl'     => "Resource Level",
1.473     amueller 3991:                 'ic'     => 'in Course',
                   3992:                 'aut'    => "Assessment URL and Title",
                   3993:                 'type'   => 'Type',
                   3994:                 'emof'   => "Enclosing Map or Folder",
                   3995:                 'part'   => 'Part',
1.472     amueller 3996:                 'pn'     => 'Parameter Name',
1.473     amueller 3997:                 'def'    => 'default',
                   3998:                 'femof'  => 'from Enclosing Map or Folder',
                   3999:                 'gen'    => 'general',
                   4000:                 'foremf' => 'for Enclosing Map or Folder',
                   4001:                 'fr'     => 'for Resource'
                   4002:             );
1.560     damieng  4003:             $r->print(<<ENDTABLETWO);
1.419     bisitz   4004: <th rowspan="3">$lt{'pie'}</th>
1.501     bisitz   4005: <th rowspan="3">$lt{'csv'}<br />($csuname:$csudom)</th>
1.578     raeburn  4006: </tr><tr><td colspan="5"></td><th colspan="2">$lt{'ic'}</th><th colspan="2">$lt{'rl'}</th>
1.419     bisitz   4007: <th colspan="1">$lt{'ic'}</th>
1.182     albertel 4008: 
1.10      www      4009: ENDTABLETWO
1.560     damieng  4010:             if ($csec) {
1.578     raeburn  4011:                 $r->print('<th colspan="3">'.
1.560     damieng  4012:                 &mt("in Section")." $csec</th>");
                   4013:             }
                   4014:             if ($cgroup) {
1.578     raeburn  4015:                 $r->print('<th colspan="3">'.
1.472     amueller 4016:                 &mt("in Group")." $cgroup</th>");
1.560     damieng  4017:             }
                   4018:             $r->print(<<ENDTABLEHEADFOUR);
1.133     www      4019: </tr><tr><th>$lt{'aut'}</th><th>$lt{'type'}</th>
                   4020: <th>$lt{'emof'}</th><th>$lt{'part'}</th><th>$lt{'pn'}</th>
1.578     raeburn  4021: <th>$lt{'gen'}</th><th>$lt{'foremf'}</th>
1.192     albertel 4022: <th>$lt{'def'}</th><th>$lt{'femof'}</th><th>$lt{'fr'}</th>
1.10      www      4023: ENDTABLEHEADFOUR
1.57      albertel 4024: 
1.560     damieng  4025:             if ($csec) {
1.578     raeburn  4026:                 $r->print('<th>'.$lt{'gen'}.'</th><th>'.$lt{'foremf'}.'</th><th>'.$lt{'fr'}.'</th>');
1.560     damieng  4027:             }
1.473     amueller 4028: 
1.560     damieng  4029:             if ($cgroup) {
1.578     raeburn  4030:                 $r->print('<th>'.$lt{'gen'}.'</th><th>'.$lt{'foremf'}.'</th><th>'.$lt{'fr'}.'</th>');
1.560     damieng  4031:             }
                   4032: 
                   4033:             if ($uname) {
                   4034:                 if (@usersgroups > 1) {
                   4035:                     $r->print('<th>'.&mt('Control by other group?').'</th>');
                   4036:                 }
1.578     raeburn  4037:                 $r->print('<th>'.$lt{'gen'}.'</th><th>'.$lt{'foremf'}.'</th><th>'.$lt{'fr'}.'</th>');
1.560     damieng  4038:             }
                   4039: 
                   4040:             $r->print('</tr>');
1.506     www      4041: #
                   4042: # Done with the headers
                   4043: # 
1.560     damieng  4044:             my $defbgone='';
                   4045:             my $defbgtwo='';
                   4046:             my $defbgthree = '';
1.57      albertel 4047: 
1.560     damieng  4048:             foreach my $rid (@ids) {
1.57      albertel 4049: 
                   4050:                 my ($inmapid)=($rid=~/\.(\d+)$/);
1.446     bisitz   4051:                 if ((!$pssymb &&
1.560     damieng  4052:                         (($pschp eq 'all') || ($allmaps{$pschp} eq $mapp{$rid})))
                   4053:                         ||
                   4054:                         ($pssymb && $pssymb eq $symbp{$rid})) {
1.4       www      4055: # ------------------------------------------------------ Entry for one resource
1.473     amueller 4056:                     if ($defbgone eq '#E0E099') {
                   4057:                         $defbgone='#E0E0DD';
1.57      albertel 4058:                     } else {
1.419     bisitz   4059:                         $defbgone='#E0E099';
1.57      albertel 4060:                     }
1.419     bisitz   4061:                     if ($defbgtwo eq '#FFFF99') {
1.473     amueller 4062:                         $defbgtwo='#FFFFDD';
1.57      albertel 4063:                     } else {
1.473     amueller 4064:                         $defbgtwo='#FFFF99';
1.57      albertel 4065:                     }
1.419     bisitz   4066:                     if ($defbgthree eq '#FFBB99') {
                   4067:                         $defbgthree='#FFBBDD';
1.269     raeburn  4068:                     } else {
1.419     bisitz   4069:                         $defbgthree='#FFBB99';
1.269     raeburn  4070:                     }
                   4071: 
1.57      albertel 4072:                     my $thistitle='';
                   4073:                     my %name=   ();
                   4074:                     undef %name;
                   4075:                     my %part=   ();
                   4076:                     my %display=();
                   4077:                     my %type=   ();
                   4078:                     my %default=();
1.196     www      4079:                     my $uri=&Apache::lonnet::declutter($uris{$rid});
1.584     raeburn  4080:                     my $toolsymb;
                   4081:                     if ($uri =~ /ext\.tool$/) {
                   4082:                         $toolsymb = $symbp{$rid};
                   4083:                     }
1.57      albertel 4084: 
1.506     www      4085:                     my $filter=$env{'form.filter'};
1.548     raeburn  4086:                     foreach my $tempkeyp (&keysplit($keyp{$rid})) {
1.57      albertel 4087:                         if (grep $_ eq $tempkeyp, @catmarker) {
1.584     raeburn  4088:                             my $parmname=&Apache::lonnet::metadata($uri,$tempkeyp.'.name',$toolsymb);
1.560     damieng  4089:     # We may only want certain parameters listed
                   4090:                             if ($filter) {
                   4091:                                 unless ($filter=~/\Q$parmname\E/) { next; }
                   4092:                             }
                   4093:                             $name{$tempkeyp}=$parmname;
1.584     raeburn  4094:                             $part{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.part',$toolsymb);
1.560     damieng  4095: 
1.584     raeburn  4096:                             my $parmdis=&Apache::lonnet::metadata($uri,$tempkeyp.'.display',$toolsymb);
1.560     damieng  4097:                             if ($allparms{$name{$tempkeyp}} ne '') {
                   4098:                                 my $identifier;
                   4099:                                 if ($parmdis =~ /(\s*\[Part.*)$/) {
                   4100:                                     $identifier = $1;
                   4101:                                 }
                   4102:                                 $display{$tempkeyp} = $allparms{$name{$tempkeyp}}.$identifier;
                   4103:                             } else {
                   4104:                                 $display{$tempkeyp} = $parmdis;
                   4105:                             }
                   4106:                             unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; }
                   4107:                             $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')';
1.584     raeburn  4108:                             $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp,$toolsymb);
                   4109:                             $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.type',$toolsymb);
                   4110:                             $thistitle=&Apache::lonnet::metadata($uri,$tempkeyp.'.title',$toolsymb);
1.57      albertel 4111:                         }
                   4112:                     }
1.548     raeburn  4113:                     my $totalparms=scalar(keys(%name));
1.57      albertel 4114:                     if ($totalparms>0) {
1.560     damieng  4115:                         my $firstrow=1;
1.473     amueller 4116:                         my $title=&Apache::lonnet::gettitle($symbp{$rid});
1.582     raeburn  4117:                         my $navmap = Apache::lonnavmaps::navmap->new();
                   4118:                         my @recurseup;
                   4119:                         if (ref($navmap) && $mapp{$rid}) {
                   4120:                             @recurseup = $navmap->recurseup_maps($mapp{$rid});
                   4121:                         }
1.419     bisitz   4122:                         $r->print('<tr><td style="background-color:'.$defbgone.';"'.
1.57      albertel 4123:                              ' rowspan='.$totalparms.
1.419     bisitz   4124:                              '><tt><font size="-1">'.
1.57      albertel 4125:                              join(' / ',split(/\//,$uri)).
                   4126:                              '</font></tt><p><b>'.
1.154     albertel 4127:                              "<a href=\"javascript:openWindow('".
1.473     amueller 4128:                           &Apache::lonnet::clutter($uri).'?symb='.
                   4129:                           &escape($symbp{$rid}).
1.336     albertel 4130:                              "', 'metadatafile', '450', '500', 'no', 'yes');\"".
                   4131:                              " target=\"_self\">$title");
1.57      albertel 4132: 
                   4133:                         if ($thistitle) {
1.473     amueller 4134:                             $r->print(' ('.$thistitle.')');
1.57      albertel 4135:                         }
                   4136:                         $r->print('</a></b></td>');
1.419     bisitz   4137:                         $r->print('<td style="background-color:'.$defbgtwo.';"'.
1.57      albertel 4138:                                       ' rowspan='.$totalparms.'>'.$typep{$rid}.
                   4139:                                       '</td>');
                   4140: 
1.419     bisitz   4141:                         $r->print('<td style="background-color:'.$defbgone.';"'.
1.57      albertel 4142:                                       ' rowspan='.$totalparms.
1.238     www      4143:                                       '>'.$maptitles{$mapp{$rid}}.'</td>');
1.548     raeburn  4144:                         foreach my $item (&keysinorder_bytype(\%name,\%keyorder)) {
1.57      albertel 4145:                             unless ($firstrow) {
                   4146:                                 $r->print('<tr>');
                   4147:                             } else {
                   4148:                                 undef $firstrow;
                   4149:                             }
1.548     raeburn  4150:                             &print_row($r,$item,\%part,\%name,\%symbp,$rid,\%default,
1.57      albertel 4151:                                        \%type,\%display,$defbgone,$defbgtwo,
1.269     raeburn  4152:                                        $defbgthree,$parmlev,$uname,$udom,$csec,
1.582     raeburn  4153:                                        $cgroup,\@usersgroups,$noeditgrp,$readonly,
                   4154:                                        \@recurseup,\%maptitles,\%allmaps_inverted,
                   4155:                                        \$numreclinks);
1.57      albertel 4156:                         }
                   4157:                     }
                   4158:                 }
                   4159:             } # end foreach ids
1.43      albertel 4160: # -------------------------------------------------- End entry for one resource
1.517     www      4161:             $r->print(&Apache::loncommon::end_data_table);
1.203     www      4162:         } # end of  full
1.57      albertel 4163: #--------------------------------------------------- Entry for parm level map
                   4164:         if ($parmlev eq 'map') {
1.419     bisitz   4165:             my $defbgone = '#E0E099';
                   4166:             my $defbgtwo = '#FFFF99';
                   4167:             my $defbgthree = '#FFBB99';
1.57      albertel 4168: 
                   4169:             my %maplist;
                   4170: 
                   4171:             if ($pschp eq 'all') {
1.446     bisitz   4172:                 %maplist = %allmaps;
1.57      albertel 4173:             } else {
                   4174:                 %maplist = ($pschp => $mapp{$pschp});
                   4175:             }
                   4176: 
                   4177: #-------------------------------------------- for each map, gather information
                   4178:             my $mapid;
1.607     raeburn  4179:             foreach $mapid (sort { $a <=> $b } keys(%maplist)) {
1.60      albertel 4180:                 my $maptitle = $maplist{$mapid};
1.57      albertel 4181: 
                   4182: #-----------------------  loop through ids and get all parameter types for map
                   4183: #-----------------------------------------          and associated information
                   4184:                 my %name = ();
                   4185:                 my %part = ();
                   4186:                 my %display = ();
                   4187:                 my %type = ();
                   4188:                 my %default = ();
                   4189:                 my $map = 0;
                   4190: 
1.473     amueller 4191: #        $r->print("Catmarker: @catmarker<br />\n");
1.446     bisitz   4192: 
1.548     raeburn  4193:                 foreach my $id (@ids) {
                   4194:                     ($map)=($id =~ /([\d]*?)\./);
                   4195:                     my $rid = $id;
1.446     bisitz   4196: 
1.57      albertel 4197: #                  $r->print("$mapid:$map:   $rid <br /> \n");
                   4198: 
1.560     damieng  4199:                     if ($map eq $mapid) {
1.473     amueller 4200:                         my $uri=&Apache::lonnet::declutter($uris{$rid});
1.584     raeburn  4201:                         my $toolsymb;
                   4202:                         if ($uri =~ /ext\.tool$/) {
                   4203:                             $toolsymb = $symbp{$rid};
                   4204:                         }
1.582     raeburn  4205: 
1.57      albertel 4206: #                    $r->print("Keys: $keyp{$rid} <br />\n");
                   4207: 
                   4208: #--------------------------------------------------------------------
                   4209: # @catmarker contains list of all possible parameters including part #s
                   4210: # $fullkeyp contains the full part/id # for the extraction of proper parameters
                   4211: # $tempkeyp contains part 0 only (no ids - ie, subparts)
                   4212: # When storing information, store as part 0
                   4213: # When requesting information, request from full part
                   4214: #-------------------------------------------------------------------
1.548     raeburn  4215:                         foreach my $fullkeyp (&keysplit($keyp{$rid})) {
                   4216:                             my $tempkeyp = $fullkeyp;
                   4217:                             $tempkeyp =~ s/_\w+_/_0_/;
1.473     amueller 4218: 
1.548     raeburn  4219:                             if ((grep $_ eq $fullkeyp, @catmarker) &&(!$name{$tempkeyp})) {
1.473     amueller 4220:                                 $part{$tempkeyp}="0";
1.584     raeburn  4221:                                 $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name',$toolsymb);
                   4222:                                 my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display',$toolsymb);
1.473     amueller 4223:                                 if ($allparms{$name{$tempkeyp}} ne '') {
                   4224:                                     my $identifier;
                   4225:                                     if ($parmdis =~ /(\s*\[Part.*)$/) {
                   4226:                                         $identifier = $1;
                   4227:                                     }
                   4228:                                     $display{$tempkeyp} = $allparms{$name{$tempkeyp}}.$identifier;
                   4229:                                 } else {
                   4230:                                     $display{$tempkeyp} = $parmdis;
                   4231:                                 }
                   4232:                                 unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; }
                   4233:                                 $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')';
                   4234:                                 $display{$tempkeyp} =~ s/_\w+_/_0_/;
1.584     raeburn  4235:                                 $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp,$toolsymb);
                   4236:                                 $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type',$toolsymb);
1.473     amueller 4237:                               }
                   4238:                         } # end loop through keys
1.560     damieng  4239:                     }
1.57      albertel 4240:                 } # end loop through ids
1.446     bisitz   4241: 
1.57      albertel 4242: #---------------------------------------------------- print header information
1.133     www      4243:                 my $foldermap=&mt($maptitle=~/^uploaded/?'Folder':'Map');
1.82      www      4244:                 my $showtitle=$maptitles{$maptitle}.($maptitle!~/^uploaded/?' ['.$maptitle.']':'');
1.401     bisitz   4245:                 my $tmp="";
1.57      albertel 4246:                 if ($uname) {
1.473     amueller 4247:                     my $person=&Apache::loncommon::plainname($uname,$udom);
1.401     bisitz   4248:                     $tmp.=&mt("User")." <font color=\"red\"><i>$uname \($person\) </i></font> ".
                   4249:                         &mt('in')." \n";
1.57      albertel 4250:                 } else {
1.401     bisitz   4251:                     $tmp.="<font color=\"red\"><i>".&mt('all').'</i></font> '.&mt('users in')." \n";
1.57      albertel 4252:                 }
1.269     raeburn  4253:                 if ($cgroup) {
1.401     bisitz   4254:                     $tmp.=&mt("Group")." <font color=\"red\"><i>$cgroup".
                   4255:                               "</i></font> ".&mt('of')." \n";
1.269     raeburn  4256:                     $csec = '';
                   4257:                 } elsif ($csec) {
1.401     bisitz   4258:                     $tmp.=&mt("Section")." <font color=\"red\"><i>$csec".
                   4259:                               "</i></font> ".&mt('of')." \n";
1.269     raeburn  4260:                 }
1.401     bisitz   4261:                 $r->print('<div align="center"><h4>'
                   4262:                          .&mt('Set Defaults for All Resources in [_1]Specifically for [_2][_3]'
1.404     bisitz   4263:                              ,$foldermap.'<br /><font color="red"><i>'.$showtitle.'</i></font><br />'
1.401     bisitz   4264:                              ,$tmp
                   4265:                              ,'<font color="red"><i>'.$coursename.'</i></font>'
                   4266:                              )
                   4267:                          ."<br /></h4>\n"
1.422     bisitz   4268:                 );
1.57      albertel 4269: #---------------------------------------------------------------- print table
1.419     bisitz   4270:                 $r->print('<p>'.&Apache::loncommon::start_data_table()
                   4271:                          .&Apache::loncommon::start_data_table_header_row()
                   4272:                          .'<th>'.&mt('Parameter Name').'</th>'
1.578     raeburn  4273:                          .'<th>'.&mt('Value').'</th>'
1.419     bisitz   4274:                          .'<th>'.&mt('Parameter in Effect').'</th>'
                   4275:                          .&Apache::loncommon::end_data_table_header_row()
                   4276:                 );
1.57      albertel 4277: 
1.582     raeburn  4278:                 my $navmap = Apache::lonnavmaps::navmap->new();
                   4279:                 my @recurseup;
                   4280:                 if (ref($navmap)) {
                   4281:                      my $mapres = $navmap->getByMapPc($mapid);
                   4282:                      if (ref($mapres)) {
                   4283:                          @recurseup = $navmap->recurseup_maps($mapres->src());
                   4284:                      }
                   4285:                 }
                   4286: 
                   4287: 
1.548     raeburn  4288:                 foreach my $item (&keysinorder(\%name,\%keyorder)) {
1.473     amueller 4289:                     $r->print(&Apache::loncommon::start_data_table_row());
1.548     raeburn  4290:                     &print_row($r,$item,\%part,\%name,\%symbp,$mapid,\%default,
1.269     raeburn  4291:                            \%type,\%display,$defbgone,$defbgtwo,$defbgthree,
1.568     raeburn  4292:                            $parmlev,$uname,$udom,$csec,$cgroup,'',$noeditgrp,
1.582     raeburn  4293:                            $readonly,\@recurseup,\%maptitles,\%allmaps_inverted,
                   4294:                            \$numreclinks);
1.57      albertel 4295:                 }
1.422     bisitz   4296:                 $r->print(&Apache::loncommon::end_data_table().'</p>'
                   4297:                          .'</div>'
                   4298:                 );
1.57      albertel 4299:             } # end each map
                   4300:         } # end of $parmlev eq map
                   4301: #--------------------------------- Entry for parm level general (Course level)
                   4302:         if ($parmlev eq 'general') {
1.473     amueller 4303:             my $defbgone = '#E0E099';
1.419     bisitz   4304:             my $defbgtwo = '#FFFF99';
                   4305:             my $defbgthree = '#FFBB99';
1.57      albertel 4306: 
                   4307: #-------------------------------------------- for each map, gather information
                   4308:             my $mapid="0.0";
                   4309: #-----------------------  loop through ids and get all parameter types for map
                   4310: #-----------------------------------------          and associated information
                   4311:             my %name = ();
                   4312:             my %part = ();
                   4313:             my %display = ();
                   4314:             my %type = ();
                   4315:             my %default = ();
1.446     bisitz   4316: 
1.548     raeburn  4317:             foreach $id (@ids) {
                   4318:                 my $rid = $id;
1.446     bisitz   4319: 
1.196     www      4320:                 my $uri=&Apache::lonnet::declutter($uris{$rid});
1.584     raeburn  4321:                 my $toolsymb;
                   4322:                 if ($uri =~ /ext\.tool$/) {
                   4323:                     $toolsymb = $symbp{$rid};
                   4324:                 }
1.57      albertel 4325: 
                   4326: #--------------------------------------------------------------------
                   4327: # @catmarker contains list of all possible parameters including part #s
                   4328: # $fullkeyp contains the full part/id # for the extraction of proper parameters
                   4329: # $tempkeyp contains part 0 only (no ids - ie, subparts)
                   4330: # When storing information, store as part 0
                   4331: # When requesting information, request from full part
                   4332: #-------------------------------------------------------------------
1.548     raeburn  4333:                 foreach my $fullkeyp (&keysplit($keyp{$rid})) {
                   4334:                     my $tempkeyp = $fullkeyp;
                   4335:                     $tempkeyp =~ s/_\w+_/_0_/;
                   4336:                     if ((grep $_ eq $fullkeyp, @catmarker) &&(!$name{$tempkeyp})) {
1.473     amueller 4337:                         $part{$tempkeyp}="0";
1.584     raeburn  4338:                         $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name',$toolsymb);
                   4339:                         my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display',$toolsymb);
1.473     amueller 4340:                         if ($allparms{$name{$tempkeyp}} ne '') {
                   4341:                             my $identifier;
                   4342:                             if ($parmdis =~ /(\s*\[Part.*)$/) {
                   4343:                                 $identifier = $1;
                   4344:                             }
                   4345:                             $display{$tempkeyp} = $allparms{$name{$tempkeyp}}.$identifier;
                   4346:                         } else {
                   4347:                             $display{$tempkeyp} = $parmdis;
                   4348:                         }
                   4349:                         unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; }
                   4350:                         $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')';
                   4351:                         $display{$tempkeyp} =~ s/_\w+_/_0_/;
1.584     raeburn  4352:                         $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp,$toolsymb);
                   4353:                         $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type',$toolsymb);
1.560     damieng  4354:                     }
1.57      albertel 4355:                 } # end loop through keys
                   4356:             } # end loop through ids
1.446     bisitz   4357: 
1.57      albertel 4358: #---------------------------------------------------- print header information
1.473     amueller 4359:             my $setdef=&mt("Set Defaults for All Resources in Course");
1.57      albertel 4360:             $r->print(<<ENDMAPONE);
1.419     bisitz   4361: <center>
                   4362: <h4>$setdef
1.135     albertel 4363: <font color="red"><i>$coursename</i></font><br />
1.57      albertel 4364: ENDMAPONE
                   4365:             if ($uname) {
1.473     amueller 4366:                 my $person=&Apache::loncommon::plainname($uname,$udom);
1.135     albertel 4367:                 $r->print(" ".&mt("User")."<font color=\"red\"> <i>$uname \($person\) </i></font> \n");
1.57      albertel 4368:             } else {
1.135     albertel 4369:                 $r->print("<i><font color=\"red\"> ".&mt("ALL")."</i> ".&mt("USERS")."</font> \n");
1.57      albertel 4370:             }
1.446     bisitz   4371: 
1.135     albertel 4372:             if ($csec) {$r->print(&mt("Section")."<font color=\"red\"> <i>$csec</i></font>\n")};
1.306     albertel 4373:             if ($cgroup) {$r->print(&mt("Group")."<font color=\"red\"> <i>$cgroup</i></font>\n")};
1.135     albertel 4374:             $r->print("</h4>\n");
1.57      albertel 4375: #---------------------------------------------------------------- print table
1.419     bisitz   4376:             $r->print('<p>'.&Apache::loncommon::start_data_table()
                   4377:                      .&Apache::loncommon::start_data_table_header_row()
                   4378:                      .'<th>'.&mt('Parameter Name').'</th>'
                   4379:                      .'<th>'.&mt('Default Value').'</th>'
                   4380:                      .'<th>'.&mt('Parameter in Effect').'</th>'
                   4381:                      .&Apache::loncommon::end_data_table_header_row()
                   4382:             );
1.57      albertel 4383: 
1.548     raeburn  4384:             foreach my $item (&keysinorder(\%name,\%keyorder)) {
1.419     bisitz   4385:                 $r->print(&Apache::loncommon::start_data_table_row());
1.548     raeburn  4386:                 &print_row($r,$item,\%part,\%name,\%symbp,$mapid,\%default,
1.568     raeburn  4387:                            \%type,\%display,$defbgone,$defbgtwo,$defbgthree,
                   4388:                            $parmlev,$uname,$udom,$csec,$cgroup,'',$noeditgrp,
                   4389:                            $readonly);
1.57      albertel 4390:             }
1.419     bisitz   4391:             $r->print(&Apache::loncommon::end_data_table()
                   4392:                      .'</p>'
                   4393:                      .'</center>'
                   4394:             );
1.57      albertel 4395:         } # end of $parmlev eq general
1.606     raeburn  4396:         $r->print('</div>');
1.43      albertel 4397:     }
1.507     www      4398:     $r->print('</form>');
1.582     raeburn  4399:     if ($numreclinks) {
                   4400:         $r->print(<<"END");
                   4401: <form name="recurseform" action="/adm/parmset?action=settable" method="post">
                   4402: <input type="hidden" name="pschp" />
                   4403: <input type="hidden" name="pscat" />
                   4404: <input type="hidden" name="psprt" />
                   4405: <input type="hidden" name="hideparmsel" value="hidden" />
                   4406: </form>
                   4407: <script type="text/javascript">
                   4408: function pjumprec(rid,name,part) {
                   4409:     document.forms.recurseform.pschp.value = rid;
                   4410:     document.forms.recurseform.pscat.value = name;
                   4411:     document.forms.recurseform.psprt.value = part;
                   4412:     document.forms.recurseform.submit();
                   4413:     return false;
                   4414: }
                   4415: </script>
                   4416: END
                   4417:     }
1.507     www      4418:     &endSettingsScreen($r);
                   4419:     $r->print(&Apache::loncommon::end_page());
1.57      albertel 4420: } # end sub assessparms
1.30      www      4421: 
1.560     damieng  4422: 
                   4423: 
1.120     www      4424: ##################################################
1.560     damieng  4425: # OVERVIEW MODE
1.207     www      4426: ##################################################
1.124     www      4427: 
1.563     damieng  4428: my $tableopen; # boolean, true if HTML table is already opened
                   4429: 
                   4430: # Returns HTML with the HTML table start tag and header, unless the table is already opened.
                   4431: # @param {boolean} $readonly - true if values cannot be edited (otherwise more columns are added)
                   4432: # @returns {string}
1.124     www      4433: sub tablestart {
1.576     raeburn  4434:     my ($readonly,$is_map) = @_;
1.124     www      4435:     if ($tableopen) {
1.552     raeburn  4436:         return '';
1.124     www      4437:     } else {
1.552     raeburn  4438:         $tableopen=1;
                   4439:         my $output = &Apache::loncommon::start_data_table().'<tr><th>'.&mt('Parameter').'</th>';
                   4440:         if ($readonly) {
                   4441:             $output .= '<th>'.&mt('Current value').'</th>';
                   4442:         } else {
1.576     raeburn  4443:             $output .= '<th>'.&mt('Delete').'</th>'.
                   4444:                        '<th>'.&mt('Set to ...').'</th>';
                   4445:             if ($is_map) {
                   4446:                 $output .= '<th>'.&mt('Recursive?').'</th>';
                   4447:             }
1.552     raeburn  4448:         }
                   4449:         $output .= '</tr>';
                   4450:         return $output;
1.124     www      4451:     }
                   4452: }
                   4453: 
1.563     damieng  4454: # Returns HTML with the HTML table end tag, unless the table is not opened.
                   4455: # @returns {string}
1.124     www      4456: sub tableend {
                   4457:     if ($tableopen) {
1.560     damieng  4458:         $tableopen=0;
                   4459:         return &Apache::loncommon::end_data_table();
1.124     www      4460:     } else {
1.560     damieng  4461:         return'';
1.124     www      4462:     }
                   4463: }
                   4464: 
1.563     damieng  4465: # Reads course and user information.
                   4466: # 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).
                   4467: # The key for student data is modified with '[useropt:'.username.':'.userdomain.'].'.
                   4468: # If the context is looking for a list, returns a list with the scalar data and the class list.
                   4469: # @param {string} $crs - course number
                   4470: # @param {string} $dom - course domain
                   4471: # @returns {hash reference|Array}
1.207     www      4472: sub readdata {
                   4473:     my ($crs,$dom)=@_;
                   4474: # Read coursedata
                   4475:     my $resourcedata=&Apache::lonnet::get_courseresdata($crs,$dom);
                   4476: # Read userdata
                   4477: 
                   4478:     my $classlist=&Apache::loncoursedata::get_classlist();
1.548     raeburn  4479:     foreach my $user (keys(%$classlist)) {
                   4480:         if ($user=~/^($match_username)\:($match_domain)$/) {
                   4481:             my ($tuname,$tudom)=($1,$2);
                   4482:             my $useropt=&Apache::lonnet::get_userresdata($tuname,$tudom);
                   4483:             foreach my $userkey (keys(%{$useropt})) {
                   4484:                 if ($userkey=~/^\Q$env{'request.course.id'}\E/) {
1.207     www      4485:                     my $newkey=$userkey;
1.548     raeburn  4486:                     $newkey=~s/^($env{'request.course.id'}\.)/$1\[useropt\:$tuname\:$tudom\]\./;
                   4487:                     $$resourcedata{$newkey}=$$useropt{$userkey};
                   4488:                 }
                   4489:             }
1.473     amueller 4490:         }
                   4491:     }
1.552     raeburn  4492:     if (wantarray) {
                   4493:         return ($resourcedata,$classlist);
                   4494:     } else {
                   4495:         return $resourcedata;
                   4496:     }
1.207     www      4497: }
                   4498: 
                   4499: 
1.563     damieng  4500: # Stores parameter data, using form parameters directly.
                   4501: #
                   4502: # 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  4503: # set_* (except settext, setipallow, setipdeny, setdeeplink, setgrace) - set a parameter value
1.563     damieng  4504: # del_* - remove a parameter
                   4505: # datepointer_* - set a date parameter (value is key_* refering to a set of other form parameters)
                   4506: # dateinterval_* - set a date interval parameter (value refers to more form parameters)
                   4507: # key_* - date values
                   4508: # days_* - for date intervals
                   4509: # hours_* - for date intervals
                   4510: # minutes_* - for date intervals
                   4511: # seconds_* - for date intervals
                   4512: # done_* - for date intervals
                   4513: # typeof_* - parameter type
                   4514: # 
                   4515: # @param {Apache2::RequestRec} $r - the Apache request
                   4516: # @param {string} $crs - course number
                   4517: # @param {string} $dom - course domain
1.208     www      4518: sub storedata {
                   4519:     my ($r,$crs,$dom)=@_;
1.207     www      4520: # Set userlevel immediately
                   4521: # Do an intermediate store of course level
                   4522:     my $olddata=&readdata($crs,$dom);
1.124     www      4523:     my %newdata=();
                   4524:     undef %newdata;
                   4525:     my @deldata=();
1.576     raeburn  4526:     my @delrec=();
                   4527:     my @delnonrec=();
1.124     www      4528:     undef @deldata;
1.504     raeburn  4529:     my ($got_chostname,$chostname,$cmajor,$cminor);
1.546     raeburn  4530:     my $now = time;
1.560     damieng  4531:     foreach my $key (keys(%env)) {
                   4532:         if ($key =~ /^form\.([a-z]+)\_(.+)$/) {
                   4533:             my $cmd=$1;
                   4534:             my $thiskey=$2;
1.576     raeburn  4535:             my ($altkey,$recursive,$tkey,$tkeyrec,$tkeynonrec);
1.622   ! raeburn  4536:             next if ($cmd eq 'rec' || $cmd eq 'settext' || $cmd eq 'setipallow' || $cmd eq 'setipdeny' || $cmd eq 'setdeeplink' || $cmd eq 'setgrace');
1.576     raeburn  4537:             if ((($cmd eq 'set') || ($cmd eq 'datepointer') || ($cmd eq 'dateinterval') || ($cmd eq 'del')) && 
                   4538:                  ($thiskey =~ /(?:sequence|page)\Q___(all)\E/)) {
                   4539:                 unless ($thiskey =~ /(encrypturl|hiddenresource)$/) {
                   4540:                     $altkey = $thiskey;
                   4541:                     $altkey =~ s/\Q___(all)\E/___(rec)/;
                   4542:                     if ($env{'form.rec_'.$thiskey}) {
                   4543:                         $recursive = 1;
                   4544:                     }
                   4545:                 }
                   4546:             }
1.560     damieng  4547:             my ($tuname,$tudom)=&extractuser($thiskey);
1.473     amueller 4548:             if ($tuname) {
1.576     raeburn  4549:                 $tkey=$thiskey;
1.560     damieng  4550:                 $tkey=~s/\.\[useropt\:$tuname\:$tudom\]\./\./;
1.576     raeburn  4551:                 if ($altkey) {
                   4552:                     $tkeynonrec = $tkey; 
                   4553:                     $tkeyrec = $altkey;
                   4554:                     $tkeyrec=~s/\.\[useropt\:$tuname\:$tudom\]\./\./;
                   4555:                 }
1.560     damieng  4556:             }
                   4557:             if ($cmd eq 'set' || $cmd eq 'datepointer' || $cmd eq 'dateinterval') {
1.563     damieng  4558:                 my ($data, $typeof, $text, $name, $valchk, $valmatch, $namematch);
                   4559:                 if ($cmd eq 'set') {
                   4560:                     $data=$env{$key};
                   4561:                     $valmatch = '';
                   4562:                     $valchk = $data;
                   4563:                     $typeof=$env{'form.typeof_'.$thiskey};
                   4564:                     $text = &mt('Saved modified parameter for');
                   4565:                     if ($typeof eq 'string_questiontype') {
                   4566:                         $name = 'type';
1.588     raeburn  4567:                     } elsif (($typeof eq 'string_lenient') || ($typeof eq 'string_deeplink')) {
                   4568:                         ($name) = ($typeof =~ /^string_(lenient|deeplink)$/);
1.563     damieng  4569:                         my $stringmatch = &standard_string_matches($typeof);
                   4570:                         if (ref($stringmatch) eq 'ARRAY') {
                   4571:                             foreach my $item (@{$stringmatch}) {
                   4572:                                 if (ref($item) eq 'ARRAY') {
                   4573:                                     my ($regexpname,$pattern) = @{$item};
                   4574:                                     if ($pattern ne '') {
                   4575:                                         if ($data =~ /$pattern/) {
                   4576:                                             $valmatch = $regexpname;
                   4577:                                             $valchk = '';
                   4578:                                             last;
                   4579:                                         }
1.560     damieng  4580:                                     }
1.549     raeburn  4581:                                 }
                   4582:                             }
                   4583:                         }
1.563     damieng  4584:                     } elsif ($typeof eq 'string_discussvote') {
                   4585:                         $name = 'discussvote';
                   4586:                     } elsif ($typeof eq 'string_examcode') {
                   4587:                         $name = 'examcode';
                   4588:                         if (&Apache::lonnet::validCODE($data)) {
                   4589:                             $valchk = 'valid';
                   4590:                         }
                   4591:                     } elsif ($typeof eq 'string_yesno') {
                   4592:                         if ($thiskey =~ /\.retrypartial$/) {
                   4593:                             $name = 'retrypartial';
                   4594:                         }
1.621     raeburn  4595:                     } elsif ($typeof eq 'string_tex') {
                   4596:                         $name = 'texdisplay';
1.549     raeburn  4597:                     }
1.563     damieng  4598:                 } elsif ($cmd eq 'datepointer') {
                   4599:                     $data=&Apache::lonhtmlcommon::get_date_from_form($env{$key});
                   4600:                     $typeof=$env{'form.typeof_'.$thiskey};
                   4601:                     $text = &mt('Saved modified date for');
                   4602:                     if ($typeof eq 'date_start') {
                   4603:                         if ($thiskey =~ /\.printstartdate$/) {
                   4604:                             $name = 'printstartdate';
                   4605:                             if (($data) && ($data > $now)) {
                   4606:                                 $valchk = 'future';
                   4607:                             }
1.560     damieng  4608:                         }
1.563     damieng  4609:                     } elsif ($typeof eq 'date_end') {
                   4610:                         if ($thiskey =~ /\.printenddate$/) {
                   4611:                             $name = 'printenddate';
                   4612:                             if (($data) && ($data < $now)) {
                   4613:                                 $valchk = 'past';
                   4614:                             }
1.560     damieng  4615:                         }
1.504     raeburn  4616:                     }
1.563     damieng  4617:                 } elsif ($cmd eq 'dateinterval') {
                   4618:                     $data=&get_date_interval_from_form($thiskey);
                   4619:                     if ($thiskey =~ /\.interval$/) {
                   4620:                         $name = 'interval';
                   4621:                         my $intervaltype = &get_intervaltype($name);
                   4622:                         my $intervalmatch = &standard_interval_matches($intervaltype);
                   4623:                         if (ref($intervalmatch) eq 'ARRAY') {
                   4624:                             foreach my $item (@{$intervalmatch}) {
                   4625:                                 if (ref($item) eq 'ARRAY') {
                   4626:                                     my ($regexpname,$pattern) = @{$item};
                   4627:                                     if ($pattern ne '') {
                   4628:                                         if ($data =~ /$pattern/) {
                   4629:                                             $valmatch = $regexpname;
                   4630:                                             $valchk = '';
                   4631:                                             last;
                   4632:                                         }
1.560     damieng  4633:                                     }
1.554     raeburn  4634:                                 }
                   4635:                             }
                   4636:                         }
                   4637:                     }
1.563     damieng  4638:                     $typeof=$env{'form.typeof_'.$thiskey};
                   4639:                     $text = &mt('Saved modified date for');
1.554     raeburn  4640:                 }
1.576     raeburn  4641:                 if ($recursive) {
1.563     damieng  4642:                     $namematch = 'maplevelrecurse';
1.560     damieng  4643:                 }
1.563     damieng  4644:                 if (($name ne '') || ($namematch ne '')) {
                   4645:                     my ($needsrelease,$needsnewer);
                   4646:                     if ($name ne '') {
                   4647:                         $needsrelease = $Apache::lonnet::needsrelease{"parameter:$name:$valchk:$valmatch:"};
1.560     damieng  4648:                         if ($needsrelease) {
                   4649:                             unless ($got_chostname) {
1.563     damieng  4650:                                 ($chostname,$cmajor,$cminor)=&parameter_release_vars();
1.560     damieng  4651:                                 $got_chostname = 1;
                   4652:                             }
1.563     damieng  4653:                             $needsnewer = &parameter_releasecheck($name,$valchk,$valmatch,undef,
                   4654:                                                                 $needsrelease,
                   4655:                                                                 $cmajor,$cminor);
                   4656:                         }
                   4657:                     }
                   4658:                     if ($namematch ne '') {
                   4659:                         if ($needsnewer) {
                   4660:                             undef($namematch);
1.560     damieng  4661:                         } else {
1.563     damieng  4662:                             my $currneeded;
                   4663:                             if ($needsrelease) {
                   4664:                                 $currneeded = $needsrelease;
                   4665:                             }
                   4666:                             $needsrelease =
                   4667:                                 $Apache::lonnet::needsrelease{"parameter::::$namematch"};
                   4668:                             if (($needsrelease) &&
                   4669:                                     (($currneeded eq '') || ($needsrelease < $currneeded))) {
                   4670:                                 unless ($got_chostname) {
                   4671:                                     ($chostname,$cmajor,$cminor) = &parameter_release_vars();
                   4672:                                     $got_chostname = 1;
                   4673:                                 }
                   4674:                                 $needsnewer = &parameter_releasecheck(undef,$valchk,$valmatch,
                   4675:                                     $namematch, $needsrelease,$cmajor,$cminor);
                   4676:                             } else {
                   4677:                                 undef($namematch);
                   4678:                             }
1.560     damieng  4679:                         }
1.557     raeburn  4680:                     }
1.563     damieng  4681:                     if ($needsnewer) {
                   4682:                         $r->print('<br />'.&oldversion_warning($name,$namematch,$data,
                   4683:                                                             $chostname,$cmajor,
                   4684:                                                             $cminor,$needsrelease));
                   4685:                         next;
                   4686:                     }
1.504     raeburn  4687:                 }
1.576     raeburn  4688:                 my ($reconlychg,$haschange,$storekey);
                   4689:                 if ($tuname) {
                   4690:                     my $ustorekey;
                   4691:                     if ($altkey) {
                   4692:                         if ($recursive) {
                   4693:                             if (exists($$olddata{$thiskey})) {
                   4694:                                 if ($$olddata{$thiskey} eq $data) {
                   4695:                                     $reconlychg = 1;
                   4696:                                 }
                   4697:                                 &Apache::lonnet::del('resourcedata',[$tkeynonrec,$tkeynonrec.'.type'],$tudom,$tuname);
                   4698:                             }
                   4699:                             if (exists($$olddata{$altkey})) {
                   4700:                                 if (defined($data) && $$olddata{$altkey} ne $data) {
                   4701:                                     $haschange = 1;
                   4702:                                 }
                   4703:                             } elsif ((!$reconlychg) && ($data ne '')) {
                   4704:                                 $haschange = 1;
                   4705:                             }
                   4706:                             $ustorekey = $tkeyrec;
                   4707:                         } else {
                   4708:                             if (exists($$olddata{$altkey})) {
                   4709:                                 if ($$olddata{$altkey} eq $data) {
                   4710:                                     $reconlychg = 1;
                   4711:                                 }
                   4712:                                 &Apache::lonnet::del('resourcedata',[$tkeyrec,$tkeyrec.'.type'],$tudom,$tuname);
                   4713:                             }
                   4714:                             if (exists($$olddata{$thiskey})) {
                   4715:                                 if (defined($data) && $$olddata{$thiskey} ne $data) {
                   4716:                                     $haschange = 1;
                   4717:                                 }
                   4718:                             } elsif ((!$reconlychg) && ($data ne '')) {
                   4719:                                 $haschange = 1;
                   4720:                             }
                   4721:                             $ustorekey = $tkeynonrec;
                   4722:                         }
                   4723:                     } else {
                   4724:                         if (exists($$olddata{$tkey})) {
                   4725:                             if (defined($data) && $$olddata{$tkey} ne $data) {
                   4726:                                 $haschange = 1;
                   4727:                             }
                   4728:                             $ustorekey = $tkey;
                   4729:                         }
                   4730:                     }
                   4731:                     if ($haschange || $reconlychg)  {
                   4732:                         unless ($env{'form.del_'.$thiskey}) {
                   4733:                             if (&Apache::lonnet::put('resourcedata',{$ustorekey=>$data,
                   4734:                                                                      $ustorekey.'.type' => $typeof},
                   4735:                                                                      $tudom,$tuname) eq 'ok') {
                   4736:                                 &log_parmset({$ustorekey=>$data,$ustorekey.'.type' => $typeof},0,$tuname,$tudom);
                   4737:                                 $r->print('<br />'.$text.' '.
                   4738:                                           &Apache::loncommon::plainname($tuname,$tudom));
                   4739:                             } else {
                   4740:                                 $r->print('<div class="LC_error">'.
                   4741:                                           &mt('Error saving parameters').'</div>');
                   4742:                             }
                   4743:                             &Apache::lonnet::devalidateuserresdata($tuname,$tudom);
                   4744:                         }
                   4745:                     }
                   4746:                 } else {
                   4747:                     if ($altkey) {
                   4748:                         if ($recursive) {
                   4749:                             if (exists($$olddata{$thiskey})) {
                   4750:                                 if ($$olddata{$thiskey} eq $data) {
                   4751:                                     $reconlychg = 1;
                   4752:                                 }
                   4753:                                 push(@delnonrec,($thiskey,$thiskey.'.type'));
                   4754:                             }
                   4755:                             if (exists($$olddata{$altkey})) {
                   4756:                                 if (defined($data) && $$olddata{$altkey} ne $data) {
                   4757:                                     $haschange = 1;
                   4758:                                 }
                   4759:                             } elsif (($data ne '') && (!$reconlychg)) {
                   4760:                                 $haschange = 1;
                   4761:                             }
                   4762:                             $storekey = $altkey;
1.563     damieng  4763:                         } else {
1.576     raeburn  4764:                             if (exists($$olddata{$altkey})) {
                   4765:                                 if ($$olddata{$altkey} eq $data) {
                   4766:                                     $reconlychg = 1;
                   4767:                                 }
                   4768:                                 push(@delrec,($altkey,$altkey.'.type'));
                   4769:                             } 
                   4770:                             if (exists($$olddata{$thiskey})) {
                   4771:                                 if (defined($data) && $$olddata{$thiskey} ne $data) {
                   4772:                                     $haschange = 1;
                   4773:                                 }
                   4774:                             } elsif (($data ne '') && (!$reconlychg)) {
                   4775:                                 $haschange = 1;
                   4776:                             }
                   4777:                             $storekey = $thiskey;
1.563     damieng  4778:                         }
1.560     damieng  4779:                     } else {
1.576     raeburn  4780:                         if (defined($data) && $$olddata{$thiskey} ne $data) {
                   4781:                             $haschange = 1;
                   4782:                             $storekey = $thiskey;
                   4783:                         }
                   4784:                     }
                   4785:                 }
                   4786:                 if ($reconlychg || $haschange) {
                   4787:                     unless ($env{'form.del_'.$thiskey}) {
                   4788:                         $newdata{$storekey}=$data;
                   4789:                         $newdata{$storekey.'.type'}=$typeof;
1.560     damieng  4790:                     }
                   4791:                 }
                   4792:             } elsif ($cmd eq 'del') {
                   4793:                 if ($tuname) {
1.576     raeburn  4794:                     my $error;
                   4795:                     if ($altkey) {  
                   4796:                         if (exists($$olddata{$altkey})) {
                   4797:                             if (&Apache::lonnet::del('resourcedata',[$tkeyrec,$tkeyrec.'.type'],$tudom,$tuname) eq 'ok') {
                   4798:                                 &log_parmset({$tkeyrec=>''},1,$tuname,$tudom);
                   4799:                                 if ($recursive) {
                   4800:                                     $r->print('<br />'.&mt('Deleted parameter for').' '.&Apache::loncommon::plainname($tuname,$tudom));
                   4801:                                 }
                   4802:                             } elsif ($recursive) {
                   4803:                                 $error = 1;
                   4804:                             }
                   4805:                         }
                   4806:                         if (exists($$olddata{$thiskey})) {
                   4807:                             if (&Apache::lonnet::del('resourcedata',[$tkeynonrec,$tkeynonrec.'.type'],$tudom,$tuname) eq 'ok') {
                   4808:                                 &log_parmset({$tkeynonrec=>''},1,$tuname,$tudom);
                   4809:                                 unless ($recursive) {
                   4810:                                     $r->print('<br />'.&mt('Deleted parameter for').' '.&Apache::loncommon::plainname($tuname,$tudom));
                   4811:                                 }
                   4812:                             } elsif (!$recursive) {
                   4813:                                 $error = 1;
                   4814:                             }
                   4815:                         }
1.560     damieng  4816:                     } else {
1.576     raeburn  4817:                         if (exists($$olddata{$thiskey})) {
                   4818:                             if (&Apache::lonnet::del('resourcedata',[$tkey,$tkey.'.type'],$tudom,$tuname) eq 'ok') {
                   4819:                                 &log_parmset({$tkey=>''},1,$tuname,$tudom);
                   4820:                                 $r->print('<br />'.&mt('Deleted parameter for').' '.&Apache::loncommon::plainname($tuname,$tudom));
                   4821:                             } else {
                   4822:                                 $error = 1;
                   4823:                             }
                   4824:                         }
                   4825:                     }
                   4826:                     if ($error) { 
1.560     damieng  4827:                         $r->print('<div class="LC_error">'.
                   4828:                             &mt('Error deleting parameters').'</div>');
                   4829:                     }
                   4830:                     &Apache::lonnet::devalidateuserresdata($tuname,$tudom);
                   4831:                 } else {
1.576     raeburn  4832:                     if ($altkey) {
                   4833:                         if (exists($$olddata{$altkey})) {
                   4834:                             unless (grep(/^\Q$altkey\E$/,@delrec)) {
                   4835:                                 push(@deldata,($altkey,$altkey.'.type'));
                   4836:                             }
                   4837:                         }
                   4838:                         if (exists($$olddata{$thiskey})) {
                   4839:                             unless (grep(/^\Q$thiskey\E$/,@delnonrec)) {
                   4840:                                 push(@deldata,($thiskey,$thiskey.'.type'));
                   4841:                             }
                   4842:                         }
                   4843:                     } elsif (exists($$olddata{$thiskey})) {
                   4844:                         push(@deldata,($thiskey,$thiskey.'.type'));
                   4845:                     }
1.560     damieng  4846:                 }
1.473     amueller 4847:             }
                   4848:         }
                   4849:     }
1.207     www      4850: # Store all course level
1.144     www      4851:     my $delentries=$#deldata+1;
1.576     raeburn  4852:     my @alldels;
                   4853:     if (@delrec) {
                   4854:         push(@alldels,@delrec);
                   4855:     }
                   4856:     if (@delnonrec) {
                   4857:         push(@alldels,@delnonrec);
                   4858:     }
                   4859:     if (@deldata) {
                   4860:         push(@alldels,@deldata);
                   4861:     }
1.548     raeburn  4862:     my @newdatakeys=keys(%newdata);
1.144     www      4863:     my $putentries=$#newdatakeys+1;
1.576     raeburn  4864:     my ($delresult,$devalidate);
                   4865:     if (@alldels) {
                   4866:         if (&Apache::lonnet::del('resourcedata',\@alldels,$dom,$crs) eq 'ok') {
                   4867:             my %loghash=map { $_ => '' } @alldels;
1.560     damieng  4868:             &log_parmset(\%loghash,1);
1.576     raeburn  4869:             if ($delentries) {
                   4870:                 $r->print('<h2>'.&mt('Deleted [quant,_1,parameter]',$delentries/2).'</h2>');
                   4871:             }
                   4872:         } elsif ($delentries) {
1.560     damieng  4873:             $r->print('<div class="LC_error">'.
                   4874:                 &mt('Error deleting parameters').'</div>');
                   4875:         }
1.576     raeburn  4876:         $devalidate = 1; 
1.144     www      4877:     }
                   4878:     if ($putentries) {
1.560     damieng  4879:         if (&Apache::lonnet::put('resourcedata',\%newdata,$dom,$crs) eq 'ok') {
                   4880:                     &log_parmset(\%newdata,0);
                   4881:             $r->print('<h3>'.&mt('Saved [quant,_1,parameter]',$putentries/2).'</h3>');
                   4882:         } else {
                   4883:             $r->print('<div class="LC_error">'.
                   4884:                 &mt('Error saving parameters').'</div>');
                   4885:         }
1.576     raeburn  4886:         $devalidate = 1; 
                   4887:     }
                   4888:     if ($devalidate) {
1.560     damieng  4889:         &Apache::lonnet::devalidatecourseresdata($crs,$dom);
1.144     www      4890:     }
1.208     www      4891: }
1.207     www      4892: 
1.563     damieng  4893: # Returns the username and domain from a key created in readdata from a resourcedata key.
                   4894: #
                   4895: # @param {string} $key - the key
                   4896: # @returns {Array}
1.208     www      4897: sub extractuser {
                   4898:     my $key=shift;
1.350     albertel 4899:     return ($key=~/^$env{'request.course.id'}.\[useropt\:($match_username)\:($match_domain)\]\./);
1.208     www      4900: }
1.206     www      4901: 
1.563     damieng  4902: # Parses a parameter key and returns the components.
                   4903: #
                   4904: # @param {string} $key - 
                   4905: # @param {hash reference} $listdata - 
                   4906: # @return {Array} - (student, resource, part, parameter)
1.381     albertel 4907: sub parse_listdata_key {
                   4908:     my ($key,$listdata) = @_;
                   4909:     # split into student/section affected, and
                   4910:     # the realm (folder/resource part and parameter
1.446     bisitz   4911:     my ($student,$realm) =
1.473     amueller 4912:     ($key=~/^\Q$env{'request.course.id'}\E\.\[([^\.]+)\]\.(.+)$/);
1.381     albertel 4913:     # if course wide student would be undefined
                   4914:     if (!defined($student)) {
1.560     damieng  4915:         ($realm)=($key=~/^\Q$env{'request.course.id'}\E\.(.+)$/);
1.381     albertel 4916:     }
                   4917:     # strip off the .type if it's not the Question type parameter
                   4918:     if ($realm=~/\.type$/ && !exists($listdata->{$key.'.type'})) {
1.560     damieng  4919:         $realm=~s/\.type//;
1.381     albertel 4920:     }
                   4921:     # split into resource+part and parameter name
1.388     albertel 4922:     my ($res,    $parm) = ($realm=~/^(.*)\.(.*)$/);
                   4923:        ($res, my $part) = ($res  =~/^(.*)\.(.*)$/);
1.381     albertel 4924:     return ($student,$res,$part,$parm);
                   4925: }
                   4926: 
1.563     damieng  4927: # Prints HTML with forms for the given parameter data in overview mode (newoverview or overview).
                   4928: #
                   4929: # @param {Apache2::RequestRec} $r - the Apache request
                   4930: # @param {hash reference} $resourcedata - parameter data returned by readdata
                   4931: # @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
                   4932: # @param {string} $sortorder - realmstudent|studentrealm
                   4933: # @param {string} $caller - name of the calling sub (overview|newoverview)
                   4934: # @param {hash reference} $classlist - from loncoursedata::get_classlist
1.568     raeburn  4935: # @param {boolean} $readonly - true if editing not allowed
1.608     raeburn  4936: # @param {string} $parmlev - full|map
                   4937: # @param {hash reference} $hash_for_realm - keys: realm, values: numeric order  
                   4938: # @param {string} $pschp - selected map pc, or 'all'
1.563     damieng  4939: # @returns{integer} - number of $listdata parameters processed
1.208     www      4940: sub listdata {
1.608     raeburn  4941:     my ($r,$resourcedata,$listdata,$sortorder,$caller,$classlist,$readonly,$parmlev,$hash_for_realm,$pschp)=@_;
1.552     raeburn  4942:     
1.207     www      4943: # Start list output
1.206     www      4944: 
1.122     www      4945:     my $oldsection='';
                   4946:     my $oldrealm='';
                   4947:     my $oldpart='';
1.123     www      4948:     my $pointer=0;
1.124     www      4949:     $tableopen=0;
1.145     www      4950:     my $foundkeys=0;
1.248     albertel 4951:     my %keyorder=&standardkeyorder();
1.594     raeburn  4952:     my $readonlyall = $readonly;
1.381     albertel 4953: 
1.552     raeburn  4954:     my ($secidx,%grouphash);
                   4955:     if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   4956:         $secidx = &Apache::loncoursedata::CL_SECTION();
1.553     raeburn  4957:         if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
                   4958:             %grouphash = &Apache::longroup::coursegroups();
                   4959:         } elsif ($env{'request.course.groups'} ne '') {
1.585     raeburn  4960:             map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'});
1.553     raeburn  4961:         }
1.552     raeburn  4962:     }
                   4963: 
1.576     raeburn  4964:     foreach my $key (sort {
1.560     damieng  4965:         my ($astudent,$ares,$apart,$aparm) = &parse_listdata_key($a,$listdata);
                   4966:         my ($bstudent,$bres,$bpart,$bparm) = &parse_listdata_key($b,$listdata);
1.608     raeburn  4967:         my ($aid,$bid);
                   4968:         if ($caller eq 'newoverview') {
                   4969:             if (ref($hash_for_realm) eq 'HASH') {
                   4970:                 if (($parmlev eq 'map') && ($pschp eq 'all')) {
                   4971:                     my ($aurl) = ($ares =~ /^(.+\.(?:sequence|page))___\(all\)$/);
                   4972:                     my ($burl) = ($bres =~ /^(.+\.(?:sequence|page))___\(all\)$/);
                   4973:                     $aid = $hash_for_realm->{$aurl};
                   4974:                     $bid = $hash_for_realm->{$burl};
                   4975:                 } elsif ($parmlev eq 'full') {
                   4976:                     $aid = $hash_for_realm->{$ares};
                   4977:                     $bid = $hash_for_realm->{$bres};
                   4978:                 }
                   4979:             }
                   4980:         }
1.381     albertel 4981: 
1.560     damieng  4982:         # get the numerical order for the param
                   4983:         $aparm=$keyorder{'parameter_0_'.$aparm};
                   4984:         $bparm=$keyorder{'parameter_0_'.$bparm};
1.381     albertel 4985: 
1.560     damieng  4986:         my $result=0;
1.381     albertel 4987: 
1.560     damieng  4988:         if ($sortorder eq 'realmstudent') {
1.381     albertel 4989:             if ($ares     ne $bres    ) {
1.608     raeburn  4990:                 if ($caller eq 'newoverview') {
                   4991:                     if (ref($hash_for_realm) eq 'HASH') {
                   4992:                         if (($parmlev eq 'map') && ($pschp eq 'all')) {
                   4993:                             $result = ($aid <=> $bid);
                   4994:                         } elsif ($parmlev eq 'full') {
                   4995:                             $result = ($aid <=> $bid);
                   4996:                         } else {
                   4997:                             $result = ($ares cmp $bres);
                   4998:                         }
                   4999:                     } else {
                   5000:                         $result = ($ares cmp $bres);
                   5001:                     }
                   5002:                 } else {
                   5003:                     $result = ($ares cmp $bres);
                   5004:                 }
1.446     bisitz   5005:             } elsif ($astudent ne $bstudent) {
1.560     damieng  5006:                 $result = ($astudent cmp $bstudent);
                   5007:             } elsif ($apart    ne $bpart   ) {
                   5008:                 $result = ($apart    cmp $bpart);
                   5009:             }
                   5010:         } else {
                   5011:             if      ($astudent ne $bstudent) {
                   5012:                 $result = ($astudent cmp $bstudent);
                   5013:             } elsif ($ares     ne $bres    ) {
1.608     raeburn  5014:                 if ($caller eq 'newoverview') {
                   5015:                     if (ref($hash_for_realm) eq 'HASH') {
                   5016:                         if (($parmlev eq 'map') && ($pschp eq 'all')) {
                   5017:                             $result = ($aid <=> $bid);
                   5018:                         } elsif ($parmlev eq 'full') {
                   5019:                             $result = ($aid <=> $bid);
                   5020:                         } else {
                   5021:                             $result = ($ares cmp $bres);
                   5022:                         }
                   5023:                     } else {
                   5024:                         $result = ($ares cmp $bres);
                   5025:                     }
                   5026:                 } else {
                   5027:                     $result = ($ares cmp $bres);
                   5028:                 }
1.560     damieng  5029:             } elsif ($apart    ne $bpart   ) {
                   5030:                 $result = ($apart    cmp $bpart);
                   5031:             }
1.473     amueller 5032:         }
1.446     bisitz   5033: 
1.560     damieng  5034:         if (!$result) {
1.381     albertel 5035:             if (defined($aparm) && defined($bparm)) {
1.560     damieng  5036:                 $result = ($aparm <=> $bparm);
1.381     albertel 5037:             } elsif (defined($aparm)) {
1.560     damieng  5038:                 $result = -1;
1.381     albertel 5039:             } elsif (defined($bparm)) {
1.560     damieng  5040:                 $result = 1;
                   5041:             }
1.473     amueller 5042:         }
1.381     albertel 5043: 
1.560     damieng  5044:         $result;
                   5045:         
1.576     raeburn  5046:     } keys(%{$listdata})) { # foreach my $key
                   5047:         my $thiskey = $key;
1.560     damieng  5048:         if ($$listdata{$thiskey.'.type'}) {
                   5049:             my $thistype=$$listdata{$thiskey.'.type'};
                   5050:             if ($$resourcedata{$thiskey.'.type'}) {
                   5051:                 $thistype=$$resourcedata{$thiskey.'.type'};
                   5052:             }
                   5053:             my ($middle,$part,$name)=
1.572     damieng  5054:                 ($thiskey=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.560     damieng  5055:             my $section=&mt('All Students');
1.594     raeburn  5056:             $readonly = $readonlyall;
1.599     raeburn  5057:             my $userscope;
1.576     raeburn  5058:             my $showval = $$resourcedata{$thiskey}; 
1.560     damieng  5059:             if ($middle=~/^\[(.*)\]/) {
                   5060:                 my $issection=$1;
                   5061:                 if ($issection=~/^useropt\:($match_username)\:($match_domain)/) {
                   5062:                     my ($stuname,$studom) = ($1,$2);
                   5063:                     if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5064:                         if (ref($classlist) eq 'HASH') {
                   5065:                             if (ref($classlist->{$stuname.':'.$studom}) eq 'ARRAY') {
                   5066:                                 next unless ($classlist->{$stuname.':'.$studom}->[$secidx] eq $env{'request.course.sec'}); 
                   5067:                             }
                   5068:                         }
                   5069:                     }
                   5070:                     $section=&mt('User').": ".&Apache::loncommon::plainname($stuname,$studom);
1.599     raeburn  5071:                     $userscope = 1;
1.560     damieng  5072:                 } else {
                   5073:                     if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5074:                         if (exists($grouphash{$issection})) {
                   5075:                             $section=&mt('Group').': '.$issection;
                   5076:                         } elsif ($issection eq $env{'request.course.sec'}) {
                   5077:                             $section = &mt('Section').': '.$issection;
                   5078:                         } else {
                   5079:                             next; 
1.552     raeburn  5080:                         }
1.560     damieng  5081:                     } else {
                   5082:                         $section=&mt('Group/Section').': '.$issection;
1.552     raeburn  5083:                     }
                   5084:                 }
1.560     damieng  5085:                 $middle=~s/^\[(.*)\]//;
                   5086:             } elsif (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) {
                   5087:                 $readonly = 1;
                   5088:             }
                   5089:             $middle=~s/\.+$//;
                   5090:             $middle=~s/^\.+//;
                   5091:             my $realm='<span class="LC_parm_scope_all">'.&mt('All Resources').'</span>';
1.576     raeburn  5092:             my ($is_map,$is_recursive,$mapurl,$maplevel);
                   5093:             if ($caller eq 'overview') {
                   5094:                 if ($middle=~/^(.+)\_\_\_\((all|rec)\)$/) {
                   5095:                     $mapurl = $1;
                   5096:                     $maplevel = $2;
                   5097:                     $is_map = 1;
                   5098:                 }
                   5099:             } elsif ($caller eq 'newoverview') {
                   5100:                 if ($middle=~/^(.+)\_\_\_\((all)\)$/) {
                   5101:                     $mapurl = $1;
                   5102:                     $maplevel = $2;
                   5103:                     $is_map = 1;
                   5104:                 }
                   5105:             }
                   5106:             if ($is_map) {
1.560     damieng  5107:                 my $leveltitle = &mt('Folder/Map');
1.615     raeburn  5108:                 my $title = &Apache::lonnet::gettitle($mapurl);
1.608     raeburn  5109:                 if (ref($hash_for_realm) eq 'HASH') {
                   5110:                     if ($hash_for_realm->{$mapurl} eq '1') {
                   5111:                         $title = &mt('Main Content');
                   5112:                     }
                   5113:                 }
1.576     raeburn  5114:                 unless (($name eq 'hiddenresource') || ($name eq 'encrypturl')) {   
                   5115:                     if ($caller eq 'newoverview') {
                   5116:                         my $altkey = $thiskey;
                   5117:                         $altkey =~ s/\Q___(all)\E/___(rec)/;
                   5118:                         if ((exists($$resourcedata{$altkey})) & (!exists($$resourcedata{$thiskey}))) {
                   5119:                             $is_recursive = 1;
                   5120:                             if ($$resourcedata{$altkey.'.type'}) {
                   5121:                                 $thistype=$$resourcedata{$altkey.'.type'};
                   5122:                             }
                   5123:                             $showval = $$resourcedata{$altkey};
                   5124:                         }
                   5125:                     } elsif (($caller eq 'overview') && ($maplevel eq 'rec')) {
                   5126:                         $thiskey =~ s/\Q___(rec)\E/___(all)/;
                   5127:                         $is_recursive = 1;
                   5128:                     }
1.560     damieng  5129:                 }
1.608     raeburn  5130:                 $realm='<span class="LC_parm_scope_folder">'.$leveltitle.': '.$title.' <br /><span class="LC_parm_folder">('.$mapurl.')</span></span>';
1.560     damieng  5131:             } elsif ($middle) {
                   5132:                 my ($map,$id,$url)=&Apache::lonnet::decode_symb($middle);
1.609     raeburn  5133:                 next if (($url =~ /\.(page|sequence)$/) && ($parmlev eq 'full') && ($caller eq 'newoverview'));
1.560     damieng  5134:                 $realm='<span class="LC_parm_scope_resource">'.&mt('Resource').
                   5135:                     ': '.&Apache::lonnet::gettitle($middle).
                   5136:                     ' <br /><span class="LC_parm_symb">('.$url.' in '.$map.' id: '.
                   5137:                     $id.')</span></span>';
                   5138:             }
                   5139:             if ($sortorder eq 'realmstudent') {
                   5140:                 if ($realm ne $oldrealm) {
                   5141:                     $r->print(&tableend()."\n<hr /><h1>$realm</h1>");
                   5142:                     $oldrealm=$realm;
                   5143:                     $oldsection='';
                   5144:                 }
                   5145:                 if ($section ne $oldsection) {
                   5146:                     $r->print(&tableend()."\n<h2>$section</h2>");
                   5147:                     $oldsection=$section;
                   5148:                     $oldpart='';
                   5149:                 }
1.552     raeburn  5150:             } else {
1.560     damieng  5151:                 if ($section ne $oldsection) {
                   5152:                     $r->print(&tableend()."\n<hr /><h1>$section</h1>");
                   5153:                     $oldsection=$section;
                   5154:                     $oldrealm='';
                   5155:                 }
                   5156:                 if ($realm ne $oldrealm) {
                   5157:                     $r->print(&tableend()."\n<h2>$realm</h2>");
                   5158:                     $oldrealm=$realm;
                   5159:                     $oldpart='';
1.552     raeburn  5160:                 }
                   5161:             }
1.560     damieng  5162:             if ($part ne $oldpart) {
                   5163:                 $r->print(&tableend().
                   5164:                     "\n".'<span class="LC_parm_part">'.&mt('Part').": $part</span>");
                   5165:                 $oldpart=$part;
1.556     raeburn  5166:             }
1.560     damieng  5167:     #
                   5168:     # Ready to print
                   5169:     #
1.470     raeburn  5170:             my $parmitem = &standard_parameter_names($name);
1.619     raeburn  5171:             my $advice;
                   5172:             if (($name eq 'mapalias') && ($middle) && (!$is_map)) {
                   5173:                 if ($middle =~ m{^uploaded/}) {
                   5174:                     $advice = &mt('Use Course Editor to set this.');
                   5175:                 } else {
                   5176:                     $advice = &mt('Use Resource Assembly Tool to set this.');
                   5177:                 }
                   5178:                 $advice = '<br /><span class="LC_fontsize_small LC_cusr_emph">'.$advice.'</span>';
                   5179:             }
1.576     raeburn  5180:             $r->print(&tablestart($readonly,$is_map).
1.560     damieng  5181:                 &Apache::loncommon::start_data_table_row().
                   5182:                 '<td><b>'.&mt($parmitem).
1.619     raeburn  5183:                 '</b>'.$advice.'</td>');
1.560     damieng  5184:             unless ($readonly) {
1.599     raeburn  5185:                 my $disabled;
                   5186:                 if (($name eq 'availablestudent') &&
                   5187:                     (($showval eq '') || ($userscope))) {
                   5188:                     $disabled = ' disabled="disabled"';
1.619     raeburn  5189:                 } elsif (($name eq 'mapalias') && ($showval eq '')) {
                   5190:                     $disabled = ' disabled="disabled"';
1.599     raeburn  5191:                 }
1.560     damieng  5192:                 $r->print('<td><input type="checkbox" name="del_'.
1.599     raeburn  5193:                         $thiskey.'"'.$disabled.' /></td>');
1.560     damieng  5194:             }
                   5195:             $r->print('<td>');
                   5196:             $foundkeys++;
                   5197:             if (&isdateparm($thistype)) {
                   5198:                 my $jskey='key_'.$pointer;
                   5199:                 my $state;
                   5200:                 $pointer++;
                   5201:                 if ($readonly) {
                   5202:                     $state = 'disabled';
                   5203:                 }
                   5204:                 $r->print(
                   5205:                     &Apache::lonhtmlcommon::date_setter('parmform',
                   5206:                                                         $jskey,
1.576     raeburn  5207:                                                         $showval,
1.560     damieng  5208:                                                         '',1,$state));
                   5209:                 unless  ($readonly) {
                   5210:                     $r->print(
                   5211:     '<input type="hidden" name="datepointer_'.$thiskey.'" value="'.$jskey.'" />'.
1.576     raeburn  5212:     (($showval!=0)?'<span class="LC_nobreak"><a href="/adm/parmset?&action=dateshift1&timebase='.$showval.'">'.
1.560     damieng  5213:     &mt('Shift all dates based on this date').'</a></span>':'').
1.576     raeburn  5214:     &date_sanity_info($showval)
1.560     damieng  5215:                     );
                   5216:                 }
                   5217:             } elsif ($thistype eq 'date_interval') {
                   5218:                 $r->print(&date_interval_selector($thiskey,$name,
1.576     raeburn  5219:                           $showval,$readonly));
1.560     damieng  5220:             } elsif ($thistype =~ m/^string/) {
1.599     raeburn  5221:                 if ($name eq 'availablestudent') {
                   5222:                     $readonly = 1;
1.619     raeburn  5223:                 } elsif (($name eq 'mapalias') && ($showval eq '')) {
                   5224:                     $readonly = 1;
1.599     raeburn  5225:                 }
1.560     damieng  5226:                 $r->print(&string_selector($thistype,$thiskey,
1.576     raeburn  5227:                           $showval,$name,$readonly));
1.560     damieng  5228:             } else {
1.576     raeburn  5229:                 $r->print(&default_selector($thiskey,$showval,$readonly));
1.552     raeburn  5230:             }
1.560     damieng  5231:             unless ($readonly) {
                   5232:                 $r->print('<input type="hidden" name="typeof_'.$thiskey.'" value="'.
                   5233:                         $thistype.'" />');
1.552     raeburn  5234:             }
1.576     raeburn  5235:             $r->print('</td>');
                   5236:             if ($is_map) {
                   5237:                 if (($name eq 'encrypturl') || ($name eq 'hiddenresource')) {
                   5238:                     $r->print('<td><table><tr><td>'.&mt('Yes').'</td></tr></table></td>');
                   5239:                 } else {
                   5240:                     my ($disabled,$recon,$recoff);
                   5241:                     if ($readonly) {
                   5242:                         $disabled = ' disabled="disabled"';
                   5243:                     }
                   5244:                     if ($is_recursive) {
                   5245:                         $recon = ' checked="checked"';
                   5246:                     } else {
                   5247:                         $recoff = ' checked="checked"';
                   5248:                     }
                   5249:                     $r->print('<td><table><tr><td><label><input type="radio" name="rec_'.$thiskey.'" value="1"'.$recon.$disabled.' />'.&mt('Yes').'</label>'.
                   5250:                               '</td><td><label><input type="radio" name="rec_'.$thiskey.'" value="0"'.$recoff.$disabled.' />'.&mt('No').'</label></td></tr></table></td>');
                   5251:                 }
                   5252:             }
                   5253:             $r->print(&Apache::loncommon::end_data_table_row());
1.473     amueller 5254:         }
1.121     www      5255:     }
1.208     www      5256:     return $foundkeys;
                   5257: }
                   5258: 
1.563     damieng  5259: # Returns a string representing the interval, directly using form data matching the given key.
                   5260: # The returned string may also include information related to proctored exams.
                   5261: # Format: seconds['_done'[':'done button title':']['_proctor'['_'proctor key]]]
                   5262: #
                   5263: # @param {string} $key - suffix for form fields related to the interval
                   5264: # @returns {string}
1.385     albertel 5265: sub get_date_interval_from_form {
                   5266:     my ($key) = @_;
                   5267:     my $seconds = 0;
1.611     raeburn  5268:     my $numnotnull = 0;
1.385     albertel 5269:     foreach my $which (['days', 86400],
1.473     amueller 5270:                ['hours', 3600],
                   5271:                ['minutes', 60],
                   5272:                ['seconds',  1]) {
1.560     damieng  5273:         my ($name, $factor) = @{ $which };
                   5274:         if (defined($env{'form.'.$name.'_'.$key})) {
1.611     raeburn  5275:             unless ($env{'form.'.$name.'_'.$key} eq '') {
                   5276:                 $numnotnull ++;
                   5277:                 $seconds += $env{'form.'.$name.'_'.$key} * $factor;
                   5278:             }
1.560     damieng  5279:         }
1.473     amueller 5280:     }
1.560     damieng  5281:     if (($key =~ /\.interval$/) &&
                   5282:             (($env{'form.done_'.$key} eq '_done') || ($env{'form.done_'.$key} eq '_done_proctor'))) {
1.559     raeburn  5283:         if ($env{'form.done_'.$key.'_buttontext'}) {
                   5284:             $env{'form.done_'.$key.'_buttontext'} =~ s/\://g;
                   5285:             $seconds .= '_done:'.$env{'form.done_'.$key.'_buttontext'}.':';
                   5286:             if ($env{'form.done_'.$key} eq '_done_proctor') {
                   5287:                 $seconds .= '_proctor';
                   5288:             }
                   5289:         } else {
                   5290:             $seconds .= $env{'form.done_'.$key}; 
                   5291:         }
                   5292:         if (($env{'form.done_'.$key} eq '_done_proctor') && 
1.560     damieng  5293:                 ($env{'form.done_'.$key.'_proctorkey'})) {
1.558     raeburn  5294:             $seconds .= '_'.$env{'form.done_'.$key.'_proctorkey'};
                   5295:         }
1.554     raeburn  5296:     }
1.611     raeburn  5297:     return if (!$numnotnull);
1.385     albertel 5298:     return $seconds;
                   5299: }
                   5300: 
                   5301: 
1.563     damieng  5302: # Returns HTML to enter a text value for a parameter.
                   5303: #
                   5304: # @param {string} $thiskey - parameter key
                   5305: # @param {string} $showval - the current value
                   5306: # @param {boolean} $readonly - true if the field should not be made editable
                   5307: # @returns {string}
1.383     albertel 5308: sub default_selector {
1.552     raeburn  5309:     my ($thiskey, $showval, $readonly) = @_;
                   5310:     my $disabled;
                   5311:     if ($readonly) {
                   5312:         $disabled = ' disabled="disabled"';
                   5313:     }
                   5314:     return '<input type="text" name="set_'.$thiskey.'" value="'.$showval.'"'.$disabled.' />';
1.383     albertel 5315: }
                   5316: 
1.563     damieng  5317: # Returns HTML to enter allow/deny rules related to IP addresses.
                   5318: #
                   5319: # @param {string} $thiskey - parameter key
                   5320: # @param {string} $showval - the current value
                   5321: # @param {boolean} $readonly - true if the fields should not be made editable
                   5322: # @returns {string}
1.549     raeburn  5323: sub string_ip_selector {
1.552     raeburn  5324:     my ($thiskey, $showval, $readonly) = @_;
1.549     raeburn  5325:     my %access = (
                   5326:                    allow => [],
                   5327:                    deny  => [],
                   5328:                  );
                   5329:     if ($showval ne '') {
                   5330:         my @current;
                   5331:         if ($showval =~ /,/) {
                   5332:             @current = split(/,/,$showval);
                   5333:         } else {
                   5334:             @current = ($showval);
                   5335:         }
                   5336:         foreach my $item (@current) {
                   5337:             if ($item =~ /^\!([\[\]a-zA-Z\.\d\*\-]+)$/) {
                   5338:                 push(@{$access{'deny'}},$1);
                   5339:             } elsif ($item =~ /^([\[\]a-zA-Z\.\d\*\-]+)$/) {
                   5340:                 push(@{$access{'allow'}},$item);
                   5341:             }
                   5342:         }
                   5343:     }
                   5344:     if (!@{$access{'allow'}}) {
                   5345:         @{$access{'allow'}} = ('');
                   5346:     }
                   5347:     if (!@{$access{'deny'}}) {
                   5348:         @{$access{'deny'}} = ('');
                   5349:     }
1.552     raeburn  5350:     my ($disabled,$addmore);
1.567     raeburn  5351:     if ($readonly) {
1.552     raeburn  5352:         $disabled=' disabled="disabled"';
                   5353:     } else {
                   5354:         $addmore = "\n".'<button class="LC_add_ipacc_button">'.&mt('Add more').'</button>';
                   5355:     }
1.549     raeburn  5356:     my $output = '<input type="hidden" name="set_'.$thiskey.'" />
                   5357: <table><tr><th>'.&mt('Allow from').'</th><th>'.&mt('Deny from').'</th></tr><tr>';
                   5358:     foreach my $acctype ('allow','deny') {
                   5359:         $output .= '
                   5360: <td valign="top">
                   5361: <div class="LC_string_ipacc_wrap" id="LC_string_ipacc_'.$acctype.'_'.$thiskey.'">
                   5362:   <div class="LC_string_ipacc_inner">'."\n";
                   5363:         my $num = 0;
                   5364:         foreach my $curr (@{$access{$acctype}}) {
1.552     raeburn  5365:             $output .= '<div><input type="text" name="setip'.$acctype.'_'.$thiskey.'" value="'.$curr.'"'.$disabled.' />';
1.549     raeburn  5366:             if ($num > 0) {
                   5367:                 $output .= '<a href="#" class="LC_remove_ipacc">'.&mt('Remove').'</a>'; 
                   5368:             }
                   5369:             $output .= '</div>'."\n";
                   5370:             $num ++;
                   5371:         }
                   5372:         $output .= '
1.552     raeburn  5373:   </div>'.$addmore.'
1.549     raeburn  5374: </div>
                   5375: </td>';
                   5376:    }
                   5377:    $output .= '
                   5378: </tr>
                   5379: </table>'."\n";
                   5380:     return $output;
                   5381: }
                   5382: 
1.588     raeburn  5383: sub string_deeplink_selector {
                   5384:     my ($thiskey, $showval, $readonly) = @_;
1.616     raeburn  5385:     my (@tables,%values,@current,%titles,%options,%optiontext,%defaults,
                   5386:         %selectnull,%domlti,%crslti,@possmenus,%components);
                   5387:     @tables = ('upper','lower');
                   5388:     %components = (
                   5389:                     upper => ['state','others','listing','scope'],
                   5390:                     lower => ['protect','menus','target','exit'],
                   5391:                   );   
1.588     raeburn  5392:     %titles = &Apache::lonlocal::texthash (
1.601     raeburn  5393:                   state   => 'Access status',
                   5394:                   others  => 'Hide other resources',
1.588     raeburn  5395:                   listing => 'In Contents and/or Gradebook',
                   5396:                   scope   => 'Access scope for link',
1.601     raeburn  5397:                   protect => 'Link protection',
1.597     raeburn  5398:                   menus   => 'Menu Items Displayed',
1.613     raeburn  5399:                   target  => 'Embedded?',
1.616     raeburn  5400:                   exit    => 'Exit Tool Button?',
1.588     raeburn  5401:               );
                   5402:     %options = (
1.601     raeburn  5403:                    state   => ['only','off','both'],
                   5404:                    others  => ['hide','unhide'],
1.588     raeburn  5405:                    listing => ['full','absent','grades','details','datestatus'],
                   5406:                    scope   => ['res','map','rec'],
1.601     raeburn  5407:                    protect => ['none','key','ltid','ltic'],
1.597     raeburn  5408:                    menus   => ['std','colls'],
1.613     raeburn  5409:                    target  => ['_self','_top'],
1.616     raeburn  5410:                    exit    => ['no','yes','url'],
1.588     raeburn  5411:                );
                   5412:     %optiontext = &Apache::lonlocal::texthash (
1.601     raeburn  5413:                     only       => 'deep only',
                   5414:                     off        => 'deeplink off',
                   5415:                     both       => 'regular + deep',
                   5416:                     hide       => 'Hidden',
                   5417:                     unhide     => 'Unhidden',
1.588     raeburn  5418:                     full       => 'Listed (linked) in both',
                   5419:                     absent     => 'Not listed',
                   5420:                     grades     => 'Listed in grades only',
                   5421:                     details    => 'Listed (unlinked) in both',
                   5422:                     datestatus => 'Listed (unlinked) inc. status in both',
                   5423:                     res        => 'resource only',
                   5424:                     map        => 'enclosing map/folder',
                   5425:                     rec        => 'recursive map/folder',
1.601     raeburn  5426:                     none       => 'not in use',
                   5427:                     key        => 'key access',
                   5428:                     ltic       => 'LTI access (course)',
                   5429:                     ltid       => 'LTI access (domain)' ,
1.597     raeburn  5430:                     std        => 'Standard (all menus)',
                   5431:                     colls      => 'Numbered collection',
1.614     raeburn  5432:                     _self      => 'Embedded',
1.613     raeburn  5433:                     _top       => 'Not embedded',
1.616     raeburn  5434:                     no         => 'Not in use',
                   5435:                     yes        => 'In use, no URL redirect',
                   5436:                     url        => 'In use, redirect to URL',  
1.597     raeburn  5437:                   );
                   5438:     %selectnull = &Apache::lonlocal::texthash (
1.601     raeburn  5439:                     ltic => 'Select Launcher',
                   5440:                     ltid => 'Select Launcher', 
1.597     raeburn  5441:                     colls => 'Select',
1.588     raeburn  5442:                   );
                   5443:     if ($showval =~ /,/) {
1.597     raeburn  5444:         %values=();
1.588     raeburn  5445:         @current = split(/,/,$showval);
1.601     raeburn  5446:         ($values{'state'}) = ($current[0] =~ /^(only|off|both)$/);
                   5447:         ($values{'others'}) = ($current[1] =~ /^(hide|unhide)$/);
                   5448:         ($values{'listing'}) = ($current[2] =~ /^(full|absent|grades|details|datestatus)$/);
                   5449:         ($values{'scope'}) = ($current[3] =~ /^(res|map|rec)$/);
                   5450:         ($values{'protect'}) = ($current[4] =~ /^(key:[a-zA-Z\d_.!\@#\$%^&*()+=-]+|ltic:\d+|ltid:\d+)$/);
                   5451:         ($values{'menus'}) = ($current[5] =~ /^(\d+)$/);
1.613     raeburn  5452:         ($values{'target'}) = ($current[6] =~ /^(_self|_top)$/);
1.616     raeburn  5453:         ($values{'exit'}) = ($current[7] =~ /^((?:(?:yes|url)(?:|\:[^:;"',]+))|no)$/);
1.588     raeburn  5454:     } else {
1.601     raeburn  5455:         $defaults{'state'} = 'off',
                   5456:         $defaults{'others'} = 'unhide',
1.588     raeburn  5457:         $defaults{'listing'} = 'full';
                   5458:         $defaults{'scope'} = 'res';
1.601     raeburn  5459:         $defaults{'protect'} = 'none';
1.597     raeburn  5460:         $defaults{'menus'} = '0';
1.613     raeburn  5461:         $defaults{'target'} = '_top';
1.616     raeburn  5462:         $defaults{'exit'} = 'yes';
1.588     raeburn  5463:     }
                   5464:     my $disabled;
                   5465:     if ($readonly) {
                   5466:         $disabled=' disabled="disabled"';
                   5467:     }
1.601     raeburn  5468:     my %courselti =
                   5469:         &Apache::lonnet::get_course_lti($env{'course.'.$env{'request.course.id'}.'.num'},
1.620     raeburn  5470:                                         $env{'course.'.$env{'request.course.id'}.'.domain'},
                   5471:                                         'provider');
1.601     raeburn  5472:     foreach my $item (keys(%courselti)) {
                   5473:         if (ref($courselti{$item}) eq 'HASH') {
                   5474:             $crslti{$item} = $courselti{$item}{'name'};
                   5475:         }
                   5476:     }
                   5477:     my %lti =
1.588     raeburn  5478:         &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'},
1.604     raeburn  5479:                                         'linkprot');
1.588     raeburn  5480:     foreach my $item (keys(%lti)) {
1.604     raeburn  5481:         if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) {
                   5482:             $domlti{$item} = $lti{$item}{'name'};
1.588     raeburn  5483:         }
                   5484:     }
1.597     raeburn  5485:     if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) {
                   5486:         foreach my $item (split(/;/,$env{'course.'.$env{'request.course.id'}.'.menucollections'})) {
                   5487:             my ($num,$value) = split(/\%/,$item);
                   5488:             if ($num =~ /^\d+$/) {
                   5489:                 push(@possmenus,$num);
                   5490:             }
                   5491:         }
                   5492:     }
                   5493: 
1.616     raeburn  5494:     my $output = '<input type="hidden" name="set_'.$thiskey.'" />';
                   5495:     foreach my $table ('upper','lower') {
                   5496:         next unless (ref($components{$table}) eq 'ARRAY');
                   5497:         $output .= '<table width="100%"><tr>';
                   5498:         foreach my $item (@{$components{$table}}) {
                   5499:             $output .= '<th>'.$titles{$item}.'</th>';
                   5500:         }
                   5501:         $output .= '</tr><tr>';
                   5502:         foreach my $item (@{$components{$table}}) {
                   5503:             $output .= '<td>';
                   5504:             if (($item eq 'protect') || ($item eq 'menus') || ($item eq 'exit')) {
                   5505:                 my $selected = $values{$item};
                   5506:                 foreach my $option (@{$options{$item}}) {
                   5507:                     if ($item eq 'protect') { 
                   5508:                         if ($option eq 'ltid') {
                   5509:                             next unless (keys(%domlti));
                   5510:                         } elsif ($option eq 'ltic') {
                   5511:                             next unless (keys(%crslti));
                   5512:                         }
                   5513:                     } elsif (($item eq 'menus') && ($option eq 'colls')) {
                   5514:                         next unless (@possmenus);
                   5515:                     }
                   5516:                     my $checked;
                   5517:                     if ($item eq 'menus') {
                   5518:                         if (($selected =~ /^\d+$/) && (@possmenus) &&
                   5519:                             (grep(/^\Q$selected\E$/,@possmenus))) {
                   5520:                             if ($option eq 'colls') {
                   5521:                                 $checked = ' checked="checked"';
                   5522:                             }
                   5523:                         } elsif (($option eq 'std') && ($selected == 0) && ($selected ne '')) {
1.597     raeburn  5524:                             $checked = ' checked="checked"';
                   5525:                         }
1.616     raeburn  5526:                     } elsif ($selected =~ /^\Q$option\E/) {
1.597     raeburn  5527:                         $checked = ' checked="checked"';
                   5528:                     }
1.616     raeburn  5529:                     my $onclick;
                   5530:                     unless ($readonly) {
                   5531:                         my $esc_key = &js_escape($thiskey);
                   5532:                         $onclick = ' onclick="toggleDeepLink(this.form,'."'$item','$esc_key'".');"';
                   5533:                     }
                   5534:                     $output .= '<span class="LC_nobreak"><label>'.
                   5535:                                '<input type="radio" name="deeplink_'.$item.'_'.$thiskey.'" value="'.$option.'"'.$onclick.$disabled.$checked.' />'."\n".
                   5536:                                $optiontext{$option}.'</label>';
                   5537:                     if (($item eq 'protect') && ($option eq 'key')) {
                   5538:                         my $visibility="hidden";
                   5539:                         my $currkey;
                   5540:                         if ($checked) {
                   5541:                             $visibility = "text";
                   5542:                             $currkey = (split(/\:/,$values{$item}))[1];
                   5543:                         }
                   5544:                         $output .= '&nbsp;'.
                   5545:                                    '<input type="'.$visibility.'" name="deeplink_'.$option.'_'.$thiskey.'" id="deeplink_'.$option.'_'.$item.'_'.$thiskey.'" value="'.$currkey.'" size="10"'.$disabled.' />';
                   5546:                     } elsif (($option eq 'ltic') || ($option eq 'ltid') || ($option eq 'colls')) {
                   5547:                         my $display="none";
                   5548:                         my ($current,$blankcheck,@possibles);
                   5549:                         if ($checked) {
                   5550:                             $display = 'inline-block';
                   5551:                             if (($option eq 'ltic') || ($option eq 'ltid'))  {
                   5552:                                 $current = (split(/\:/,$selected))[1];
                   5553:                             } else {
                   5554:                                 $current = $selected;
                   5555:                             }
1.597     raeburn  5556:                         } else {
1.616     raeburn  5557:                             $blankcheck = ' selected="selected"';
1.597     raeburn  5558:                         }
1.601     raeburn  5559:                         if ($option eq 'ltid') {
1.616     raeburn  5560:                             @possibles = keys(%domlti);
1.601     raeburn  5561:                         } elsif ($option eq 'ltic') {
1.616     raeburn  5562:                             @possibles = keys(%crslti); 
                   5563:                         } else {
                   5564:                             @possibles = @possmenus;
                   5565:                         }
                   5566:                         $output .= '<div id="deeplinkdiv_'.$option.'_'.$item.'_'.$thiskey.'"'.
                   5567:                                    ' style="display: '.$display.'">&nbsp;<select name="'.
                   5568:                                    'deeplink_'.$option.'_'.$thiskey.'"'.$disabled.'>';
                   5569:                         if (@possibles > 1) {
                   5570:                             $output .= '<option value=""'.$blankcheck.'>'.$selectnull{$option}.
                   5571:                                        '</option>'."\n";
                   5572:                         }
                   5573:                         foreach my $poss (sort { $a <=> $b } @possibles) {
                   5574:                             my $selected;
                   5575:                             if (($poss == $current) || (scalar(@possibles) ==1)) {
                   5576:                                 $selected = ' selected="selected"';
                   5577:                             }
                   5578:                             my $shown = $poss;
                   5579:                             if ($option eq 'ltid') {
                   5580:                                 $shown = $domlti{$poss};
                   5581:                             } elsif ($option eq 'ltic') {
                   5582:                                 $shown = $crslti{$poss};
                   5583:                             }
                   5584:                             $output .= '<option value="'.$poss.'"'.$selected.'>'.$shown.'</option>';
                   5585:                         }
                   5586:                         $output .= '</select></div>';
                   5587:                     }
                   5588:                     $output .= '</span> ';
                   5589:                 }
                   5590:                 if ($item eq 'exit') {
                   5591:                     my $exitsty = 'none';
                   5592:                     my $displayval;
                   5593:                     if ($values{$item} =~ /^(yes|url)/) { 
                   5594:                         $exitsty = 'inline-block';
                   5595:                         my $currval = (split(/\:/,$values{$item}))[1];
                   5596:                         if ($currval eq '') {
                   5597:                             $displayval = 'Exit Tool';
                   5598:                         } else {
                   5599:                             $displayval = $currval;
1.597     raeburn  5600:                         }
1.588     raeburn  5601:                     }
1.616     raeburn  5602:                     $output .= '<div id="deeplinkdiv_'.$item.'_'.$thiskey.'"'.
                   5603:                                ' style="display: '.$exitsty.'"><br />'.&mt('Button text').': '.
                   5604:                                '<input type="text" name="deeplink_exittext_'.$thiskey.'"'.
                   5605:                                ' id="deeplink_exittext_'.$thiskey.'" value="'.$displayval.'"'.
                   5606:                                ' size="10"'.$disabled.' /></div>';
1.588     raeburn  5607:                 }
1.616     raeburn  5608:             } else {
                   5609:                 my $selected = $values{$item};
                   5610:                 my $defsel;
                   5611:                 if ($selected eq '') {
                   5612:                     $defsel = ' selected="selected"';
                   5613:                 }
                   5614:                 $output .= '<select name="deeplink_'.$item.'_'.$thiskey.'"'.$disabled.'>'."\n".
                   5615:                            '<option value=""'.$defsel.'>'.&mt('Please select').'</option>'."\n";
                   5616:                 foreach my $option (@{$options{$item}}) {
                   5617:                     $output .= '<option value="'.$option.'"';
                   5618:                     if ($option eq $selected) {
                   5619:                         $output .= ' selected="selected"';
                   5620:                     }
                   5621:                     $output .= '>'.$optiontext{$option}.'</option>';
1.588     raeburn  5622:                 }
1.616     raeburn  5623:                 $output .= '</select>';
1.588     raeburn  5624:             }
1.616     raeburn  5625:             $output .= '</td>';
                   5626:         }
                   5627:         $output .= '</tr></table>'."\n";
                   5628:         if ($table eq 'upper') {
                   5629:             $output .= '<br />';
1.588     raeburn  5630:         }
                   5631:     }
                   5632:     return $output;
                   5633: }
                   5634: 
1.622   ! raeburn  5635: sub string_grace_selector {
        !          5636:     my ($thiskey, $showval, $readonly) = @_;
        !          5637:     my $addmore;
        !          5638:     unless ($readonly) {
        !          5639:         $addmore = "\n".'<button class="LC_add_grace_button">'.&mt('Add more').'</button>';
        !          5640:     }
        !          5641:     my $output = '<input type="hidden" name="set_'.$thiskey.'" value="" />'.
        !          5642:                  '<div class="LC_string_grace_wrap" id="LC_string_grace_'.$thiskey.'">'."\n".
        !          5643:                  '<div class="LC_string_grace_inner">'."\n";
        !          5644:     if ($showval ne '') {
        !          5645:         my @current;
        !          5646:         if ($showval =~ /,/) {
        !          5647:             @current = split(/,/,$showval);
        !          5648:         } else {
        !          5649:             @current = ($showval);
        !          5650:         }
        !          5651:         my $num = scalar(@current);	
        !          5652:         foreach my $item (@current) {
        !          5653:             my ($delta,$fraction,$gradational) = split(/:/,$item);
        !          5654:             if (($delta =~ /^\d+$/) && ($fraction =~ /^(0|1)\.?\d*$/) && 
        !          5655:                 (($gradational eq 1) || ($gradational eq '0'))) {
        !          5656:                 my $gradchk = '';
        !          5657:                 if ($gradational) {
        !          5658:                     $gradchk = ' checked="checked"';
        !          5659:                 }
        !          5660:                 $output .= &grace_form($thiskey,$delta,$fraction,$gradchk,
        !          5661:                                        $readonly);
        !          5662:             }
        !          5663:         }
        !          5664:     } elsif (!$readonly) {
        !          5665:         $output .= &grace_form($thiskey,'','','',$readonly);
        !          5666:     }
        !          5667:     $output .= '</div>'.$addmore.'</div>';
        !          5668:     return $output;
        !          5669: }
        !          5670: 
        !          5671: sub grace_form {
        !          5672:     my ($thiskey,$delta,$fraction,$gradchkon,$readonly) = @_;
        !          5673:     my $disabled;
        !          5674:     if ($readonly) {
        !          5675:         $disabled = ' disabled="disabled"';
        !          5676:     }
        !          5677:     my %lt = &grace_titles();
        !          5678:     my $output = '<div><input type="hidden" name="setgrace_'.$thiskey.'" value="" />'.
        !          5679:                  '<fieldset class="LC_grace"><legend>'.$lt{'sinc'}.'</legend>';
        !          5680:     foreach my $which (['days', 86400, 31],
        !          5681:                        ['hours', 3600, 23],
        !          5682:                        ['minutes', 60, 59],
        !          5683:                        ['seconds',  1, 59]) {
        !          5684:         my ($name, $factor, $max) = @{ $which };
        !          5685:         my $amount;
        !          5686:         if ($delta ne '') {
        !          5687:             $amount = int($delta/$factor);
        !          5688:             $delta %= $factor;
        !          5689:         }
        !          5690:         my %select = ((map {$_ => $_} (0..$max)),
        !          5691:                       'select_form_order' => [0..$max]);
        !          5692:         $output .= &Apache::loncommon::select_form($amount,$name.'_'.$thiskey,
        !          5693:                                                    \%select,'',$readonly);
        !          5694:         $output .= '&nbsp;'.$lt{$name}.'&nbsp;&nbsp; ';
        !          5695:     }
        !          5696:     $output .= '</fieldset>'.
        !          5697:                '<fieldset class="LC_grace"><legend>'.$lt{'pcr'}.'</legend>'.
        !          5698:                '<input type="text" size="3" name="frac_'.$thiskey.'" value="'.$fraction.'"'.$disabled.' />'.
        !          5699:                '&nbsp;&nbsp;<label><input type="checkbox" value="1" name="grad_'.$thiskey.'"'.$gradchkon.$disabled.' />'.
        !          5700:                $lt{'grad'}.'</label></fieldset>';
        !          5701:     unless ($readonly) {
        !          5702:         $output .= '<a href="#" class="LC_remove_grace">'.$lt{'remo'}.'</a>';
        !          5703:     }
        !          5704:     $output .= '</div>'."\n";
        !          5705:     return $output;
        !          5706: }
        !          5707: 
        !          5708: sub grace_titles {
        !          5709:     return &Apache::lonlocal::texthash (
        !          5710:                                          sinc => 'Time past due',
        !          5711:                                          remo => 'Remove',
        !          5712:                                          pcr => 'Partial credit',
        !          5713:                                          grad => 'gradual',
        !          5714:                                          days => 'days',
        !          5715:                                          hours => 'hours',
        !          5716:                                          minutes => 'minutes',
        !          5717:                                          seconds => 'seconds',
        !          5718:     );
        !          5719: }
1.560     damieng  5720: 
                   5721: { # block using some constants related to parameter types (overview mode)
                   5722: 
1.446     bisitz   5723: my %strings =
1.383     albertel 5724:     (
                   5725:      'string_yesno'
                   5726:              => [[ 'yes', 'Yes' ],
1.560     damieng  5727:                  [ 'no', 'No' ]],
1.383     albertel 5728:      'string_problemstatus'
                   5729:              => [[ 'yes', 'Yes' ],
1.473     amueller 5730:          [ 'answer', 'Yes, and show correct answer if they exceed the maximum number of tries.' ],
                   5731:          [ 'no', 'No, don\'t show correct/incorrect feedback.' ],
                   5732:          [ 'no_feedback_ever', 'No, show no feedback at all.' ]],
1.504     raeburn  5733:      'string_questiontype'
                   5734:              => [[ 'problem', 'Standard Problem'],
                   5735:                  [ 'survey', 'Survey'],
                   5736:                  [ 'anonsurveycred', 'Anonymous Survey (credit for submission)'],
1.530     bisitz   5737:                  [ 'exam', 'Bubblesheet Exam'],
1.504     raeburn  5738:                  [ 'anonsurvey', 'Anonymous Survey'],
                   5739:                  [ 'randomizetry', 'New Randomization Each N Tries (default N=1)'],
                   5740:                  [ 'practice', 'Practice'],
                   5741:                  [ 'surveycred', 'Survey (credit for submission)']],
1.514     raeburn  5742:      'string_lenient'
                   5743:              => [['yes', 'Yes' ],
                   5744:                  [ 'no', 'No' ],
1.549     raeburn  5745:                  [ 'default', 'Default - only bubblesheet grading is lenient' ],
                   5746:                  [ 'weighted', 'Yes, weighted (optionresponse in checkbox mode)' ]],
1.521     raeburn  5747:      'string_discussvote'
                   5748:              => [['yes','Yes'],
                   5749:                  ['notended','Yes, unless discussion ended'],
                   5750:                  ['no','No']],
1.549     raeburn  5751:      'string_ip'
                   5752:              => [['_allowfrom_','Hostname(s), or IP(s) from which access is allowed'],
1.587     raeburn  5753:                  ['_denyfrom_','Hostname(s) or IP(s) from which access is disallowed']], 
                   5754:      'string_deeplink'
1.616     raeburn  5755:              => [['on','Set choices for link protection, resource listing, access scope, shown menu items, embedding, and exit link']],
1.621     raeburn  5756:      'string_tex'
                   5757:              => [['tth', 'tth (TeX to HTML)'],
                   5758:                  ['mathjax', 'MathJax']],
1.622   ! raeburn  5759:      'string_grace'
        !          5760:              => [['on','Set grading scale and grace period for submissions after due date']],
1.587     raeburn  5761:     );
                   5762:    
1.383     albertel 5763: 
1.549     raeburn  5764: my %stringmatches = (
                   5765:          'string_lenient'
                   5766:               => [['weighted','^\-?[.\d]+,\-?[.\d]+,\-?[.\d]+,\-?[.\d]+$'],],
                   5767:          'string_ip'
                   5768:               => [['_allowfrom_','[^\!]+'],
                   5769:                   ['_denyfrom_','\!']],
1.588     raeburn  5770:          'string_deeplink'
1.616     raeburn  5771:               => [['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  5772:          'string_grace'
        !          5773:               => [['on','^\d+,(0|1)\.?\d*,(0|1)']],
1.549     raeburn  5774:     );
                   5775: 
                   5776: my %stringtypes = (
                   5777:                     type         => 'string_questiontype',
                   5778:                     lenient      => 'string_lenient',
                   5779:                     retrypartial => 'string_yesno',
                   5780:                     discussvote  => 'string_discussvote',
                   5781:                     examcode     => 'string_examcode',
                   5782:                     acc          => 'string_ip',
1.587     raeburn  5783:                     deeplink     => 'string_deeplink',
1.622   ! raeburn  5784:                     grace        => 'string_grace',
1.621     raeburn  5785:                     texdisplay   => 'string_tex',
1.549     raeburn  5786:                   );
                   5787: 
1.563     damieng  5788: # Returns the possible values and titles for a given string type, or undef if there are none.
                   5789: # Used by courseprefs.
                   5790: #
                   5791: # @param {string} $string_type - a parameter type for strings
                   5792: # @returns {array reference} - 2D array, containing values and English titles
1.505     raeburn  5793: sub standard_string_options {
                   5794:     my ($string_type) = @_;
                   5795:     if (ref($strings{$string_type}) eq 'ARRAY') {
                   5796:         return $strings{$string_type};
                   5797:     }
                   5798:     return;
                   5799: }
1.383     albertel 5800: 
1.563     damieng  5801: # Returns regular expressions to match kinds of string types, or undef if there are none.
                   5802: #
                   5803: # @param {string} $string_type - a parameter type for strings
                   5804: # @returns {array reference}  - 2D array, containing regular expression names and regular expressions
1.549     raeburn  5805: sub standard_string_matches {
                   5806:     my ($string_type) = @_;
                   5807:     if (ref($stringmatches{$string_type}) eq 'ARRAY') {
                   5808:         return $stringmatches{$string_type};
                   5809:     }
                   5810:     return;
                   5811: }
                   5812: 
1.563     damieng  5813: # Returns a parameter type for a given parameter with a string type, or undef if not known.
                   5814: #
                   5815: # @param {string} $name - parameter name
                   5816: # @returns {string}
1.549     raeburn  5817: sub get_stringtype {
                   5818:     my ($name) = @_;
                   5819:     if (exists($stringtypes{$name})) {
                   5820:         return $stringtypes{$name};
                   5821:     }
                   5822:     return;
                   5823: }
                   5824: 
1.563     damieng  5825: # Returns HTML to edit a string parameter.
                   5826: #
                   5827: # @param {string} $thistype - parameter type
                   5828: # @param {string} $thiskey - parameter key
                   5829: # @param {string} $showval - parameter current value
                   5830: # @param {string} $name - parameter name
                   5831: # @param {boolean} $readonly - true if the values should not be made editable
                   5832: # @returns {string}
1.383     albertel 5833: sub string_selector {
1.552     raeburn  5834:     my ($thistype, $thiskey, $showval, $name, $readonly) = @_;
1.446     bisitz   5835: 
1.383     albertel 5836:     if (!exists($strings{$thistype})) {
1.552     raeburn  5837:         return &default_selector($thiskey,$showval,$readonly);
1.383     albertel 5838:     }
                   5839: 
1.504     raeburn  5840:     my %skiptype;
1.514     raeburn  5841:     if (($thistype eq 'string_questiontype') || 
1.560     damieng  5842:             ($thistype eq 'string_lenient') ||
                   5843:             ($thistype eq 'string_discussvote') ||
                   5844:             ($thistype eq 'string_ip') ||
1.588     raeburn  5845:             ($thistype eq 'string_deeplink') ||
1.621     raeburn  5846:             ($thistype eq 'string_tex') ||
1.622   ! raeburn  5847:             ($thistype eq 'string_grace') ||
1.560     damieng  5848:             ($name eq 'retrypartial')) {
1.504     raeburn  5849:         my ($got_chostname,$chostname,$cmajor,$cminor); 
                   5850:         foreach my $possibilities (@{ $strings{$thistype} }) {
                   5851:             next unless (ref($possibilities) eq 'ARRAY');
1.514     raeburn  5852:             my ($parmval, $description) = @{ $possibilities };
1.549     raeburn  5853:             my $parmmatch;
                   5854:             if (ref($stringmatches{$thistype}) eq 'ARRAY') {
                   5855:                 foreach my $item (@{$stringmatches{$thistype}}) {
                   5856:                     if (ref($item) eq 'ARRAY') {
                   5857:                         if ($parmval eq $item->[0]) {
                   5858:                             $parmmatch = $parmval;
                   5859:                             $parmval = '';
                   5860:                             last;
                   5861:                         }
                   5862:                     }
                   5863:                 }
                   5864:             }
                   5865:             my $needsrelease=$Apache::lonnet::needsrelease{"parameter:$name:$parmval:$parmmatch"}; 
1.504     raeburn  5866:             if ($needsrelease) {
                   5867:                 unless ($got_chostname) {
1.514     raeburn  5868:                     ($chostname,$cmajor,$cminor)=&parameter_release_vars();
1.504     raeburn  5869:                     $got_chostname = 1;
                   5870:                 }
1.557     raeburn  5871:                 my $needsnewer=&parameter_releasecheck($name,$parmval,$parmmatch,undef,
1.549     raeburn  5872:                                                        $needsrelease,$cmajor,$cminor);
1.504     raeburn  5873:                 if ($needsnewer) {
1.549     raeburn  5874:                     if ($parmmatch ne '') {
                   5875:                         $skiptype{$parmmatch} = 1;
                   5876:                     } elsif ($parmval ne '') {
                   5877:                         $skiptype{$parmval} = 1;
                   5878:                     }
1.504     raeburn  5879:                 }
                   5880:             }
                   5881:         }
                   5882:     }
1.549     raeburn  5883: 
                   5884:     if ($thistype eq 'string_ip') {
1.622   ! raeburn  5885:         return &string_ip_selector($thiskey,$showval,$readonly);
        !          5886:     } elsif ($thistype eq 'string_grace') {
        !          5887:         return &string_grace_selector($thiskey,$showval,$readonly);
1.588     raeburn  5888:     } elsif ($thistype eq 'string_deeplink') {
                   5889:         return &string_deeplink_selector($thiskey,$showval,$readonly);
1.549     raeburn  5890:     }
1.504     raeburn  5891: 
1.552     raeburn  5892:     my ($result,$disabled);
                   5893: 
                   5894:     if ($readonly) {
                   5895:         $disabled = ' disabled="disabled"';
                   5896:     }
1.504     raeburn  5897:     my $numinrow = 3;
                   5898:     if ($thistype eq 'string_problemstatus') {
                   5899:         $numinrow = 2;
                   5900:     } elsif ($thistype eq 'string_questiontype') {
                   5901:         if (keys(%skiptype) > 0) {
                   5902:              $numinrow = 4;
                   5903:         }
                   5904:     }
                   5905:     my $rem;
                   5906:     if (ref($strings{$thistype}) eq 'ARRAY') {
                   5907:         my $i=0;
                   5908:         foreach my $possibilities (@{ $strings{$thistype} }) {
                   5909:             next unless (ref($possibilities) eq 'ARRAY');
                   5910:             my ($name, $description) = @{ $possibilities };
1.549     raeburn  5911:             next if ($skiptype{$name});
1.504     raeburn  5912:             $rem = $i%($numinrow);
                   5913:             if ($rem == 0) {
                   5914:                 if ($i > 0) {
                   5915:                     $result .= '</tr>';
                   5916:                 }
                   5917:                 $result .= '<tr>';
                   5918:             }
1.549     raeburn  5919:             my $colspan;
                   5920:             if ($i == @{ $strings{$thistype} }-1) {
                   5921:                 $rem = @{ $strings{$thistype} }%($numinrow);
                   5922:                 if ($rem) {
                   5923:                     my $colsleft = $numinrow - $rem;
                   5924:                     if ($colsleft) {
                   5925:                         $colspan = $colsleft+1;
                   5926:                         $colspan = ' colspan="'.$colspan.'"';
                   5927:                     }
                   5928:                 }
                   5929:             }
                   5930:             my ($add,$onchange,$css_class);
                   5931:             if ($thistype eq 'string_lenient') {
                   5932:                 if ($name eq 'weighted') {
                   5933:                     my $display;
                   5934:                     my %relatives = &Apache::lonlocal::texthash(
                   5935:                                         corrchkd     => 'Correct (checked)',
                   5936:                                         corrunchkd   => 'Correct (unchecked)',
                   5937:                                         incorrchkd   => 'Incorrect (checked)',
                   5938:                                         incorrunchkd => 'Incorrect (unchecked)',
                   5939:                     );
                   5940:                     my %textval = (
                   5941:                                     corrchkd     => '1.0',
                   5942:                                     corrunchkd   => '1.0',
                   5943:                                     incorrchkd   => '0.0',
                   5944:                                     incorrunchkd => '0.0',
                   5945:                     );
                   5946:                     if ($showval =~ /^([\-\d\.]+)\,([\-\d\.]+)\,([\-\d\.]+)\,([\-\d\.]+)$/) {
                   5947:                         $textval{'corrchkd'} = $1;
                   5948:                         $textval{'corrunchkd'} = $2;
                   5949:                         $textval{'incorrchkd'} = $3;
                   5950:                         $textval{'incorrunchkd'} = $4;
                   5951:                         $display = 'inline';
                   5952:                         $showval = $name;
                   5953:                     } else {
                   5954:                         $display = 'none';
                   5955:                     }
                   5956:                     $add = ' <div id="LC_parmtext_'.$thiskey.'" style="display:'.$display.'"><table>'.
                   5957:                            '<tr><th colspan="2">'.&mt("Foil's submission status").'</th><th>'.&mt('Points').'</th></tr>';  
                   5958:                     foreach my $reltype ('corrchkd','corrunchkd','incorrchkd','incorrunchkd') {
                   5959:                         $add .= '<tr><td>&nbsp;</td><td>'.$relatives{$reltype}.'</td>'."\n".
                   5960:                                 '<td><input type="text" name="settext_'.$thiskey.'"'.
1.552     raeburn  5961:                                 ' value="'.$textval{$reltype}.'" size="3"'.$disabled.' />'.
1.549     raeburn  5962:                                 '</td></tr>';
                   5963:                     }
                   5964:                     $add .= '</table></div>'."\n";
                   5965:                 }
                   5966:                 $onchange = ' onclick="javascript:toggleParmTextbox(this.form,'."'$thiskey'".');"';
                   5967:                 $css_class = ' class="LC_lenient_radio"';
                   5968:             }
                   5969:             $result .= '<td class="LC_left_item"'.$colspan.'>'.
1.504     raeburn  5970:                        '<span class="LC_nobreak"><label>'.
                   5971:                        '<input type="radio" name="set_'.$thiskey.
1.552     raeburn  5972:                        '" value="'.$name.'"'.$onchange.$css_class.$disabled;
1.504     raeburn  5973:             if ($showval eq $name) {
                   5974:                 $result .= ' checked="checked"';
                   5975:             }
1.549     raeburn  5976:             $result .= ' />'.&mt($description).'</label>'.$add.'</span></td>';
1.504     raeburn  5977:             $i++;
                   5978:         }
                   5979:         $result .= '</tr>';
1.473     amueller 5980:     }
1.504     raeburn  5981:     if ($result) {
                   5982:         $result = '<table border="0">'.$result.'</table>';
1.383     albertel 5983:     }
                   5984:     return $result;
                   5985: }
                   5986: 
1.554     raeburn  5987: my %intervals =
                   5988:     (
                   5989:      'date_interval'
                   5990:              => [[ 'done', 'Yes' ],
1.558     raeburn  5991:                  [ 'done_proctor', 'Yes, with proctor key'],                  
1.554     raeburn  5992:                  [ '', 'No' ]],
                   5993:     );
                   5994: 
                   5995: my %intervalmatches = (
                   5996:          'date_interval'
1.559     raeburn  5997:               => [['done','\d+_done(|\:[^\:]+\:)$'],
                   5998:                   ['done_proctor','\d+_done(|\:[^\:]+\:)_proctor_']],
1.554     raeburn  5999:     );
                   6000: 
                   6001: my %intervaltypes = (
                   6002:                       interval => 'date_interval',
                   6003:     );
                   6004: 
1.563     damieng  6005: # Returns regular expressions to match kinds of interval type, or undef if there are none.
                   6006: #
                   6007: # @param {string} $interval_type - a parameter type for intervals
                   6008: # @returns {array reference}  - 2D array, containing regular expression names and regular expressions
1.554     raeburn  6009: sub standard_interval_matches {
                   6010:     my ($interval_type) = @_;
                   6011:     if (ref($intervalmatches{$interval_type}) eq 'ARRAY') {
                   6012:         return $intervalmatches{$interval_type};
                   6013:     }
                   6014:     return;
                   6015: }
                   6016: 
1.563     damieng  6017: # Returns a parameter type for a given parameter with an interval type, or undef if not known.
                   6018: #
                   6019: # @param {string} $name - parameter name
                   6020: # @returns {string}
1.554     raeburn  6021: sub get_intervaltype {
                   6022:     my ($name) = @_;
                   6023:     if (exists($intervaltypes{$name})) {
                   6024:         return $intervaltypes{$name};
                   6025:     }
                   6026:     return;
                   6027: }
                   6028: 
1.563     damieng  6029: # Returns the possible values and titles for a given interval type, or undef if there are none.
                   6030: # Used by courseprefs.
                   6031: #
                   6032: # @param {string} $interval_type - a parameter type for intervals
                   6033: # @returns {array reference} - 2D array, containing values and English titles
1.554     raeburn  6034: sub standard_interval_options {
                   6035:     my ($interval_type) = @_;
                   6036:     if (ref($intervals{$interval_type}) eq 'ARRAY') {
                   6037:         return $intervals{$interval_type};
                   6038:     }
                   6039:     return;
                   6040: }
                   6041: 
1.563     damieng  6042: # Returns HTML to edit a date interval parameter.
                   6043: #
                   6044: # @param {string} $thiskey - parameter key
                   6045: # @param {string} $name - parameter name
                   6046: # @param {string} $showval - parameter current value
                   6047: # @param {boolean} $readonly - true if the values should not be made editable
                   6048: # @returns {string}
1.554     raeburn  6049: sub date_interval_selector {
                   6050:     my ($thiskey, $name, $showval, $readonly) = @_;
                   6051:     my ($result,%skipval);
                   6052:     if ($name eq 'interval') {
                   6053:         my $intervaltype = &get_intervaltype($name);
                   6054:         my ($got_chostname,$chostname,$cmajor,$cminor);
                   6055:         foreach my $possibilities (@{ $intervals{$intervaltype} }) {
                   6056:             next unless (ref($possibilities) eq 'ARRAY');
                   6057:             my ($parmval, $description) = @{ $possibilities };
                   6058:             my $parmmatch;
                   6059:             if (ref($intervalmatches{$intervaltype}) eq 'ARRAY') {
                   6060:                 foreach my $item (@{$intervalmatches{$intervaltype}}) {
                   6061:                     if (ref($item) eq 'ARRAY') {
                   6062:                         if ($parmval eq $item->[0]) {
                   6063:                             $parmmatch = $parmval;
                   6064:                             $parmval = '';
                   6065:                             last;
                   6066:                         }
                   6067:                     }
                   6068:                 }
                   6069:             }
                   6070:             my $needsrelease=$Apache::lonnet::needsrelease{"parameter:$name:$parmval:$parmmatch"};
                   6071:             if ($needsrelease) {
                   6072:                 unless ($got_chostname) {
                   6073:                     ($chostname,$cmajor,$cminor)=&parameter_release_vars();
                   6074:                     $got_chostname = 1;
                   6075:                 }
1.557     raeburn  6076:                 my $needsnewer=&parameter_releasecheck($name,$parmval,$parmmatch,undef,
1.554     raeburn  6077:                                                        $needsrelease,$cmajor,$cminor);
                   6078:                 if ($needsnewer) {
                   6079:                     if ($parmmatch ne '') {
                   6080:                         $skipval{$parmmatch} = 1;
                   6081:                     } elsif ($parmval ne '') {
                   6082:                         $skipval{$parmval} = 1;
                   6083:                     }
                   6084:                 }
                   6085:             }
                   6086:         }
                   6087:     }
                   6088: 
                   6089:     my $currval = $showval;
                   6090:     foreach my $which (['days', 86400, 31],
                   6091:                ['hours', 3600, 23],
                   6092:                ['minutes', 60, 59],
                   6093:                ['seconds',  1, 59]) {
1.560     damieng  6094:         my ($name, $factor, $max) = @{ $which };
                   6095:         my $amount = int($showval/$factor);
                   6096:         $showval  %= $factor;
                   6097:         my %select = ((map {$_ => $_} (0..$max)),
                   6098:                 'select_form_order' => [0..$max]);
1.611     raeburn  6099:         if ($currval eq '') {
                   6100:             unshift(@{$select{'select_form_order'}},'');
                   6101:             $select{''} = '';
                   6102:             $amount = '';
                   6103:         }
1.560     damieng  6104:         $result .= &Apache::loncommon::select_form($amount,$name.'_'.$thiskey,
                   6105:                             \%select,'',$readonly);
                   6106:         $result .= ' '.&mt($name);
1.554     raeburn  6107:     }
                   6108:     if ($name eq 'interval') {
                   6109:         unless ($skipval{'done'}) {
                   6110:             my $checkedon = '';
1.611     raeburn  6111:             my $checkedoff = '';
1.558     raeburn  6112:             my $checkedproc = '';
                   6113:             my $currproctorkey = '';
                   6114:             my $currprocdisplay = 'hidden';
1.559     raeburn  6115:             my $currdonetext = &mt('Done');
                   6116:             if ($currval =~ /^(?:\d+)_done$/) {
                   6117:                 $checkedon = ' checked="checked"';
                   6118:             } elsif ($currval =~ /^(?:\d+)_done\:([^\:]+)\:$/) {
                   6119:                 $currdonetext = $1;
1.554     raeburn  6120:                 $checkedon = ' checked="checked"';
1.558     raeburn  6121:             } elsif ($currval =~ /^(?:\d+)_done_proctor_(.+)$/) {
                   6122:                 $currproctorkey = $1;
                   6123:                 $checkedproc = ' checked="checked"';
                   6124:                 $currprocdisplay = 'text';
1.559     raeburn  6125:             } elsif ($currval =~ /^(?:\d+)_done\:([^\:]+)\:_proctor_(.+)$/) {
                   6126:                 $currdonetext = $1;
                   6127:                 $currproctorkey = $2;
                   6128:                 $checkedproc = ' checked="checked"';
                   6129:                 $currprocdisplay = 'text';
1.611     raeburn  6130:             } elsif ($currval ne '') {
                   6131:                 $checkedoff = ' checked="checked"';
                   6132:             } else {
                   6133:                 $currdonetext = '';
1.554     raeburn  6134:             }
1.558     raeburn  6135:             my $onclick = ' onclick="toggleSecret(this.form,'."'done_','$thiskey'".');"';
1.567     raeburn  6136:             my $disabled;
                   6137:             if ($readonly) {
                   6138:                 $disabled = ' disabled="disabled"';
                   6139:             }
1.558     raeburn  6140:             $result .= '<br /><span class="LC_nobreak">'.&mt('Include "done" button').
1.567     raeburn  6141:                        '<label><input type="radio" value="" name="done_'.$thiskey.'"'.$checkedoff.$onclick.$disabled.' />'.
1.558     raeburn  6142:                        &mt('No').'</label>'.('&nbsp;'x2).
1.567     raeburn  6143:                        '<label><input type="radio" value="_done" name="done_'.$thiskey.'"'.$checkedon.$onclick.$disabled.' />'.
1.558     raeburn  6144:                        &mt('Yes').'</label>'.('&nbsp;'x2).
1.567     raeburn  6145:                        '<label><input type="radio" value="_done_proctor" name="done_'.$thiskey.'"'.$checkedproc.$onclick.$disabled.' />'.
1.558     raeburn  6146:                        &mt('Yes, with proctor key').'</label>'.
                   6147:                        '<input type="'.$currprocdisplay.'" id="done_'.$thiskey.'_proctorkey" '.
1.567     raeburn  6148:                        'name="done_'.$thiskey.'_proctorkey" value="'.&HTML::Entities::encode($currproctorkey,'"<>&').'"'.$disabled.' /></span><br />'.
1.559     raeburn  6149:                        '<span class="LC_nobreak">'.&mt('Button text').': '.
1.611     raeburn  6150:                        '<input type="text" name="done_'.$thiskey.'_buttontext" id="done_'.$thiskey.'_buttontext" value="'.
                   6151:                        &HTML::Entities::encode($currdonetext,'"<>&').'"'.$disabled.' /></span>';
1.554     raeburn  6152:         }
                   6153:     }
                   6154:     unless ($readonly) {
                   6155:         $result .= '<input type="hidden" name="dateinterval_'.$thiskey.'" />';
                   6156:     }
                   6157:     return $result;
                   6158: }
                   6159: 
1.563     damieng  6160: # Returns HTML with a warning if a parameter requires a more recent version of LON-CAPA.
                   6161: #
                   6162: # @param {string} $name - parameter name
                   6163: # @param {string} $namematch - parameter level name (recognized: resourcelevel|maplevel|maplevelrecurse|courselevel)
                   6164: # @param {string} $value - parameter value
                   6165: # @param {string} $chostname - course server name
                   6166: # @param {integer} $cmajor - major version number
                   6167: # @param {integer} $cminor - minor version number
                   6168: # @param {string} $needsrelease - release version needed (major.minor)
                   6169: # @returns {string}
1.549     raeburn  6170: sub oldversion_warning {
1.557     raeburn  6171:     my ($name,$namematch,$value,$chostname,$cmajor,$cminor,$needsrelease) = @_;
                   6172:     my $standard_name = &standard_parameter_names($name);
                   6173:     if ($namematch) {
                   6174:         my $level = &standard_parameter_levels($namematch);
                   6175:         my $msg = '';
                   6176:         if ($level) {
                   6177:             $msg = &mt('[_1] was [_2]not[_3] set at the level of: [_4].',
                   6178:                        $standard_name,'<b>','</b>','"'.$level.'"');
                   6179:         } else {
                   6180:             $msg = &mt('[_1] was [_2]not[_3] set.',
                   6181:                       $standard_name,'<b>','</b>');
                   6182:         }
                   6183:         return '<p class="LC_warning">'.$msg.'<br />'.
                   6184:                &mt('LON-CAPA version ([_1]) installed on home server ([_2]) does not meet version requirements ([_3] or newer).',
                   6185:                    $cmajor.'.'.$cminor,$chostname,
                   6186:                    $needsrelease).
                   6187:                    '</p>';
                   6188:     }
1.549     raeburn  6189:     my $desc;
                   6190:     my $stringtype = &get_stringtype($name);
                   6191:     if ($stringtype ne '') {
                   6192:         if ($name eq 'examcode') {
                   6193:             $desc = $value;
                   6194:         } elsif (ref($strings{$stringtypes{$name}}) eq 'ARRAY') {
                   6195:             foreach my $possibilities (@{ $strings{$stringtypes{$name}} }) {
                   6196:                 next unless (ref($possibilities) eq 'ARRAY');
                   6197:                 my ($parmval, $description) = @{ $possibilities };
                   6198:                 my $parmmatch;
                   6199:                 if (ref($stringmatches{$stringtypes{$name}}) eq 'ARRAY') {
                   6200:                     foreach my $item (@{$stringmatches{$stringtypes{$name}}}) {
                   6201:                         if (ref($item) eq 'ARRAY') {
                   6202:                             my ($regexpname,$pattern) = @{$item};
                   6203:                             if ($parmval eq $regexpname) {
                   6204:                                 if ($value =~ /$pattern/) {
                   6205:                                     $desc = $description; 
                   6206:                                     $parmmatch = 1;
                   6207:                                     last;
                   6208:                                 }
                   6209:                             }
                   6210:                         }
                   6211:                     }
                   6212:                     last if ($parmmatch);
                   6213:                 } elsif ($parmval eq $value) {
                   6214:                     $desc = $description;
                   6215:                     last;
                   6216:                 }
                   6217:             }
                   6218:         }
                   6219:     } elsif (($name eq 'printstartdate') || ($name eq 'printenddate')) {
                   6220:         my $now = time;
                   6221:         if ($value =~ /^\d+$/) {
                   6222:             if ($name eq 'printstartdate') {
                   6223:                 if ($value > $now) {
                   6224:                     $desc = &Apache::lonlocal::locallocaltime($value);
                   6225:                 }
                   6226:             } elsif ($name eq 'printenddate') {
                   6227:                 if ($value < $now) {
                   6228:                     $desc = &Apache::lonlocal::locallocaltime($value);
                   6229:                 }
                   6230:             }
                   6231:         }
                   6232:     }
                   6233:     return '<p class="LC_warning">'.
1.557     raeburn  6234:        &mt('[_1] was [_2]not[_3] set to [_4].',
                   6235:            $standard_name,'<b>','</b>','"'.$desc.'"').'<br />'.
                   6236:        &mt('LON-CAPA version ([_1]) installed on home server ([_2]) does not meet version requirements ([_3] or newer).',
                   6237:        $cmajor.'.'.$cminor,$chostname,
                   6238:        $needsrelease).
                   6239:        '</p>';
1.549     raeburn  6240: }
                   6241: 
1.560     damieng  6242: } # end of block using some constants related to parameter types
                   6243: 
1.549     raeburn  6244: 
1.563     damieng  6245: 
                   6246: # Shifts all start and end dates in the current course by $shift.
1.389     www      6247: #
1.563     damieng  6248: # @param {integer} $shift - time to shift, in seconds
                   6249: # @returns {string} - error name or 'ok'
1.389     www      6250: sub dateshift {
1.594     raeburn  6251:     my ($shift,$numchanges)=@_;
1.389     www      6252:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6253:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.594     raeburn  6254:     my $sec = $env{'request.course.sec'};
1.595     raeburn  6255:     my $secgrpregex;
                   6256:     if ($sec ne '') {
                   6257:         my @groups;
                   6258:         if ($env{'request.course.groups'} ne '') {
                   6259:             @groups = split(/:/,$env{'request.course.groups'});
                   6260:         }
                   6261:         if (@groups) {
                   6262:             $secgrpregex = '(?:'.join('|',($sec,@groups)).')';
                   6263:         } else {
                   6264:             $secgrpregex = $sec;
                   6265:         }
                   6266:     }
1.389     www      6267:     my %data=&Apache::lonnet::dump('resourcedata',$dom,$crs);
                   6268: # ugly retro fix for broken version of types
1.548     raeburn  6269:     foreach my $key (keys(%data)) {
1.389     www      6270:         if ($key=~/\wtype$/) {
                   6271:             my $newkey=$key;
                   6272:             $newkey=~s/type$/\.type/;
                   6273:             $data{$newkey}=$data{$key};
                   6274:             delete $data{$key};
                   6275:         }
                   6276:     }
1.391     www      6277:     my %storecontent=();
1.389     www      6278: # go through all parameters and look for dates
1.548     raeburn  6279:     foreach my $key (keys(%data)) {
1.389     www      6280:        if ($data{$key.'.type'}=~/^date_(start|end)$/) {
1.594     raeburn  6281:           if ($sec ne '') {
1.595     raeburn  6282:               next unless ($key =~ /^$env{'request.course.id'}\.\[$secgrpregex\]\./);
1.594     raeburn  6283:           }
1.389     www      6284:           my $newdate=$data{$key}+$shift;
1.594     raeburn  6285:           $$numchanges ++;
1.391     www      6286:           $storecontent{$key}=$newdate;
1.389     www      6287:        }
                   6288:     }
1.391     www      6289:     my $reply=&Apache::lonnet::cput
                   6290:                 ('resourcedata',\%storecontent,$dom,$crs);
                   6291:     if ($reply eq 'ok') {
                   6292:        &log_parmset(\%storecontent);
                   6293:     }
                   6294:     &Apache::lonnet::devalidatecourseresdata($crs,$dom);
                   6295:     return $reply;
1.389     www      6296: }
                   6297: 
1.563     damieng  6298: # Overview mode UI to edit course parameters.
                   6299: #
                   6300: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      6301: sub newoverview {
1.568     raeburn  6302:     my ($r,$parm_permission) = @_;
1.280     albertel 6303: 
1.208     www      6304:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6305:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6306:     my $crstype =  $env{'course.'.$env{'request.course.id'}.'.type'};
1.568     raeburn  6307:     my $readonly = 1;
                   6308:     if ($parm_permission->{'edit'}) {
                   6309:         undef($readonly);
                   6310:     }
1.414     droeschl 6311:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview',
1.473     amueller 6312:         text=>"Overview Mode"});
1.523     raeburn  6313: 
                   6314:     my %loaditems = (
1.549     raeburn  6315:                       'onload'   => "showHide_courseContent(); resize_scrollbox('mapmenuscroll','1','1'); showHideLenient();",
1.523     raeburn  6316:                     );
                   6317:     my $js = '
                   6318: <script type="text/javascript">
                   6319: // <![CDATA[
                   6320: '.
                   6321:             &Apache::lonhtmlcommon::resize_scrollbox_js('params')."\n".
                   6322:             &showhide_js()."\n".
1.549     raeburn  6323:             &toggleparmtextbox_js()."\n".
                   6324:             &validateparms_js()."\n".
                   6325:             &ipacc_boxes_js()."\n".
1.622   ! raeburn  6326:             &grace_js()."\n".
1.558     raeburn  6327:             &done_proctor_js()."\n".
1.588     raeburn  6328:             &deeplink_js()."\n".
1.523     raeburn  6329: '// ]]>
                   6330: </script>
                   6331: ';
1.549     raeburn  6332: 
1.523     raeburn  6333:     my $start_page = &Apache::loncommon::start_page('Set Parameters',$js,
                   6334:                                                     {'add_entries' => \%loaditems,});
1.298     albertel 6335:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview');
1.507     www      6336:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6337:     &startSettingsScreen($r,'parmset',$crstype);
1.208     www      6338:     $r->print(<<ENDOVER);
1.549     raeburn  6339: <form method="post" action="/adm/parmset?action=newoverview" name="parmform" onsubmit="return validateParms();">
1.208     www      6340: ENDOVER
1.211     www      6341:     my @ids=();
                   6342:     my %typep=();
                   6343:     my %keyp=();
                   6344:     my %allparms=();
                   6345:     my %allparts=();
                   6346:     my %allmaps=();
                   6347:     my %mapp=();
                   6348:     my %symbp=();
                   6349:     my %maptitles=();
                   6350:     my %uris=();
                   6351:     my %keyorder=&standardkeyorder();
                   6352:     my %defkeytype=();
                   6353: 
                   6354:     my %alllevs=();
                   6355:     $alllevs{'Resource Level'}='full';
1.215     www      6356:     $alllevs{'Map/Folder Level'}='map';
1.211     www      6357:     $alllevs{'Course Level'}='general';
                   6358: 
                   6359:     my $csec=$env{'form.csec'};
1.269     raeburn  6360:     my $cgroup=$env{'form.cgroup'};
1.211     www      6361: 
                   6362:     my @pscat=&Apache::loncommon::get_env_multiple('form.pscat');
                   6363:     my $pschp=$env{'form.pschp'};
1.506     www      6364: 
1.211     www      6365:     my @psprt=&Apache::loncommon::get_env_multiple('form.psprt');
1.516     www      6366:     if (!@psprt) { $psprt[0]='all'; }
1.211     www      6367: 
1.446     bisitz   6368:     my @selected_sections =
1.473     amueller 6369:     &Apache::loncommon::get_env_multiple('form.Section');
1.211     www      6370:     @selected_sections = ('all') if (! @selected_sections);
1.374     albertel 6371:     foreach my $sec (@selected_sections) {
                   6372:         if ($sec eq 'all') {
1.211     www      6373:             @selected_sections = ('all');
                   6374:         }
                   6375:     }
1.552     raeburn  6376:     if ($env{'request.course.sec'} ne '') {
                   6377:         @selected_sections = ($env{'request.course.sec'});
                   6378:     }
1.269     raeburn  6379:     my @selected_groups =
                   6380:         &Apache::loncommon::get_env_multiple('form.Group');
1.211     www      6381: 
                   6382:     my $pssymb='';
                   6383:     my $parmlev='';
1.446     bisitz   6384: 
1.211     www      6385:     unless ($env{'form.parmlev'}) {
                   6386:         $parmlev = 'map';
                   6387:     } else {
                   6388:         $parmlev = $env{'form.parmlev'};
                   6389:     }
                   6390: 
1.446     bisitz   6391:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 6392:                 \%mapp, \%symbp,\%maptitles,\%uris,
1.603     raeburn  6393:                 \%keyorder,\%defkeytype,$pssymb);
1.211     www      6394: 
1.374     albertel 6395:     if (grep {$_ eq 'all'} (@psprt)) {
1.481     amueller 6396:         @psprt = keys(%allparts);
1.374     albertel 6397:     }
1.211     www      6398: # Menu to select levels, etc
                   6399: 
1.456     bisitz   6400:     $r->print('<div class="LC_Box">');
1.445     neumanie 6401:     #$r->print('<h2 class="LC_hcell">Step 1</h2>');
1.452     bisitz   6402:     $r->print('<div>');
1.523     raeburn  6403:     $r->print(&Apache::lonhtmlcommon::start_pick_box(undef,'parmlevel'));
1.211     www      6404:     &levelmenu($r,\%alllevs,$parmlev);
1.610     raeburn  6405:     $r->print(&Apache::lonhtmlcommon::row_closure());
                   6406:     &mapmenu($r,\%allmaps,$pschp,\%maptitles,\%symbp,$parmlev);
1.447     bisitz   6407:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.445     neumanie 6408:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   6409:     $r->print('</div></div>');
1.446     bisitz   6410: 
1.456     bisitz   6411:     $r->print('<div class="LC_Box">');
1.452     bisitz   6412:     $r->print('<div>');
1.581     raeburn  6413:     &displaymenu($r,\%allparms,\@pscat,\%keyorder);
1.453     schualex 6414:     $r->print(&Apache::lonhtmlcommon::start_pick_box());
1.446     bisitz   6415:     $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parts to View')));
1.553     raeburn  6416:     my $sectionselector = &sectionmenu(\@selected_sections);
                   6417:     my $groupselector = &groupmenu(\@selected_groups);
1.481     amueller 6418:     $r->print('<table>'.
1.553     raeburn  6419:               '<tr><th>'.&mt('Parts').'</th>');
                   6420:     if ($sectionselector) {
                   6421:         $r->print('<th>'.&mt('Section(s)').'</th>');
                   6422:     }
                   6423:     if ($groupselector) {
                   6424:         $r->print('<th>'.&mt('Group(s)').'</th>');
                   6425:     }
                   6426:     $r->print('</tr><tr><td>');
1.211     www      6427:     &partmenu($r,\%allparts,\@psprt);
1.553     raeburn  6428:     $r->print('</td>');
                   6429:     if ($sectionselector) { 
                   6430:         $r->print('<td>'.$sectionselector.'</td>');
                   6431:     }
                   6432:     if ($groupselector) {
                   6433:         $r->print('<td>'.$groupselector.'</td>');
                   6434:     }
                   6435:     $r->print('</tr></table>');
1.447     bisitz   6436:     $r->print(&Apache::lonhtmlcommon::row_closure(1));
1.445     neumanie 6437:     $r->print(&Apache::lonhtmlcommon::end_pick_box());
                   6438:     $r->print('</div></div>');
                   6439: 
1.456     bisitz   6440:     $r->print('<div class="LC_Box">');
1.452     bisitz   6441:     $r->print('<div>');
1.214     www      6442:     my $sortorder=$env{'form.sortorder'};
                   6443:     unless ($sortorder) { $sortorder='realmstudent'; }
1.612     raeburn  6444:     &sortmenu($r,$sortorder,'newoverview');
1.445     neumanie 6445:     $r->print('</div></div>');
1.446     bisitz   6446: 
1.214     www      6447:     $r->print('<p><input type="submit" name="dis" value="'.&mt('Display').'" /></p>');
1.446     bisitz   6448: 
1.211     www      6449: # Build the list data hash from the specified parms
                   6450: 
                   6451:     my $listdata;
                   6452:     %{$listdata}=();
                   6453: 
                   6454:     foreach my $cat (@pscat) {
1.269     raeburn  6455:         &secgroup_lister($cat,$pschp,$parmlev,$listdata,\@psprt,\@selected_sections,\%defkeytype,\%allmaps,\@ids,\%symbp);
                   6456:         &secgroup_lister($cat,$pschp,$parmlev,$listdata,\@psprt,\@selected_groups,\%defkeytype,\%allmaps,\@ids,\%symbp);
1.211     www      6457:     }
                   6458: 
1.212     www      6459:     if (($env{'form.store'}) || ($env{'form.dis'})) {
1.211     www      6460: 
1.481     amueller 6461:         if ($env{'form.store'}) { &storedata($r,$crs,$dom); }
1.211     www      6462: 
                   6463: # Read modified data
                   6464: 
1.481     amueller 6465:         my $resourcedata=&readdata($crs,$dom);
1.211     www      6466: 
                   6467: # List data
                   6468: 
1.608     raeburn  6469:         my $hash_for_realm;
                   6470:         if (($parmlev eq 'map') && (keys(%allmaps))) {
                   6471:             %{$hash_for_realm} = reverse(%allmaps);
                   6472:         } elsif (($parmlev eq 'full') && (keys(%symbp))) {
                   6473:             for (my $i=0; $i<@ids; $i++) {
                   6474:                 $hash_for_realm->{$symbp{$ids[$i]}} = $i;
                   6475:             }
                   6476:         }
                   6477:         &listdata($r,$resourcedata,$listdata,$sortorder,'newoverview',undef,$readonly,$parmlev,$hash_for_realm,$pschp);
1.568     raeburn  6478:     }
                   6479:     $r->print(&tableend());
                   6480:     unless ($readonly) {
                   6481:         $r->print( ((($env{'form.store'}) || ($env{'form.dis'}))?'<p><input type="submit" name="store" value="'.&mt('Save').'" /></p>':'') );
1.211     www      6482:     }
1.568     raeburn  6483:     $r->print('</form>');
1.507     www      6484:     &endSettingsScreen($r);
                   6485:     $r->print(&Apache::loncommon::end_page());
1.208     www      6486: }
                   6487: 
1.563     damieng  6488: # Fills $listdata with parameter information.
                   6489: # Keys use the format course id.[section id].part.name and course id.[section id].part.name.type.
                   6490: # The non-type value is always 1.
                   6491: #
                   6492: # @param {string} $cat - parameter name
1.566     damieng  6493: # @param {string} $pschp - selected map pc, or 'all'
1.563     damieng  6494: # @param {string} $parmlev - selected level value (full|map|general), or ''
                   6495: # @param {hash reference} $listdata - the parameter data that will be modified
                   6496: # @param {array reference} $psprt - selected parts
                   6497: # @param {array reference} $selections - selected sections
                   6498: # @param {hash reference} $defkeytype - hash parameter name -> parameter type
1.566     damieng  6499: # @param {hash reference} $allmaps - hash map pc -> map src
                   6500: # @param {array reference} $ids - resource and map ids
                   6501: # @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' or resource symb
1.269     raeburn  6502: sub secgroup_lister {
                   6503:     my ($cat,$pschp,$parmlev,$listdata,$psprt,$selections,$defkeytype,$allmaps,$ids,$symbp) = @_;
                   6504:     foreach my $item (@{$selections}) {
                   6505:         foreach my $part (@{$psprt}) {
                   6506:             my $rootparmkey=$env{'request.course.id'};
                   6507:             if (($item ne 'all') && ($item ne 'none') && ($item)) {
                   6508:                 $rootparmkey.='.['.$item.']';
                   6509:             }
                   6510:             if ($parmlev eq 'general') {
                   6511: # course-level parameter
                   6512:                 my $newparmkey=$rootparmkey.'.'.$part.'.'.$cat;
                   6513:                 $$listdata{$newparmkey}=1;
                   6514:                 $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6515:             } elsif ($parmlev eq 'map') {
                   6516: # map-level parameter
1.548     raeburn  6517:                 foreach my $mapid (keys(%{$allmaps})) {
1.269     raeburn  6518:                     if (($pschp ne 'all') && ($pschp ne $mapid)) { next; }
                   6519:                     my $newparmkey=$rootparmkey.'.'.$$allmaps{$mapid}.'___(all).'.$part.'.'.$cat;
                   6520:                     $$listdata{$newparmkey}=1;
                   6521:                     $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6522:                 }
                   6523:             } else {
                   6524: # resource-level parameter
                   6525:                 foreach my $rid (@{$ids}) {
                   6526:                     my ($map,$resid,$url)=&Apache::lonnet::decode_symb($$symbp{$rid});
                   6527:                     if (($pschp ne 'all') && ($$allmaps{$pschp} ne $map)) { next; }
                   6528:                     my $newparmkey=$rootparmkey.'.'.$$symbp{$rid}.'.'.$part.'.'.$cat;
                   6529:                     $$listdata{$newparmkey}=1;
                   6530:                     $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat};
                   6531:                 }
                   6532:             }
                   6533:         }
                   6534:     }
                   6535: }
                   6536: 
1.563     damieng  6537: # UI to edit parameter settings starting with a list of all existing parameters.
                   6538: # (called by setoverview action)
                   6539: #
                   6540: # @param {Apache2::RequestRec} $r - the Apache request
1.208     www      6541: sub overview {
1.568     raeburn  6542:     my ($r,$parm_permission) = @_;
1.208     www      6543:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6544:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6545:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.568     raeburn  6546:     my $readonly = 1;
                   6547:     if ($parm_permission->{'edit'}) {
                   6548:         undef($readonly);
                   6549:     }
1.549     raeburn  6550:     my $js = '<script type="text/javascript">'."\n".
                   6551:              '// <![CDATA['."\n".
                   6552:              &toggleparmtextbox_js()."\n".
                   6553:              &validateparms_js()."\n".
                   6554:              &ipacc_boxes_js()."\n".
1.622   ! raeburn  6555:              &grace_js()."\n".
1.558     raeburn  6556:              &done_proctor_js()."\n".
1.588     raeburn  6557:              &deeplink_js()."\n".
1.549     raeburn  6558:              '// ]]>'."\n".
                   6559:              '</script>'."\n";
1.414     droeschl 6560:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview',
1.473     amueller 6561:     text=>"Overview Mode"});
1.549     raeburn  6562:     my %loaditems = (
                   6563:                       'onload'   => "showHideLenient();",
                   6564:                     );
                   6565: 
                   6566:     my $start_page=&Apache::loncommon::start_page('Modify Parameters',$js,{'add_entries' => \%loaditems,});
1.298     albertel 6567:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview');
1.507     www      6568:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6569:     &startSettingsScreen($r,'parmset',$crstype);
1.549     raeburn  6570:     $r->print('<form method="post" action="/adm/parmset?action=setoverview" name="parmform" onsubmit="return validateParms();">');
1.507     www      6571: 
1.208     www      6572: # Store modified
                   6573: 
1.568     raeburn  6574:     unless ($readonly) {
                   6575:         &storedata($r,$crs,$dom);
                   6576:     }
1.208     www      6577: 
                   6578: # Read modified data
                   6579: 
1.552     raeburn  6580:     my ($resourcedata,$classlist)=&readdata($crs,$dom);
1.208     www      6581: 
1.214     www      6582: 
                   6583:     my $sortorder=$env{'form.sortorder'};
                   6584:     unless ($sortorder) { $sortorder='realmstudent'; }
1.608     raeburn  6585:     &sortmenu($r,$sortorder,'overview');
1.214     www      6586: 
1.568     raeburn  6587:     my $submitbutton = '<input type="submit" value="'.&mt('Save').'" />';
                   6588: 
                   6589:     if ($readonly) {
                   6590:         $r->print('<p>'.$submitbutton.'</p>');
                   6591:     }
                   6592: 
1.208     www      6593: # List data
                   6594: 
1.568     raeburn  6595:     my $foundkeys=&listdata($r,$resourcedata,$resourcedata,$sortorder,'overview',$classlist,$readonly);
                   6596:     $r->print(&tableend().'<p>');
                   6597:     if ($foundkeys) {
                   6598:         unless ($readonly) {
                   6599:             $r->print('<p>'.$submitbutton.'</p>');
                   6600:         }
                   6601:     } else {
                   6602:         $r->print('<p class="LC_info">'.&mt('There are no parameters.').'</p>');
                   6603:     }
                   6604:     $r->print('</form>'.&Apache::loncommon::end_page());
1.120     www      6605: }
1.121     www      6606: 
1.560     damieng  6607: # Unused sub.
1.563     damieng  6608: #
                   6609: # @param {Apache2::RequestRec} $r - the Apache request
1.333     albertel 6610: sub clean_parameters {
                   6611:     my ($r) = @_;
                   6612:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6613:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
                   6614: 
1.414     droeschl 6615:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=cleanparameters',
1.473     amueller 6616:         text=>"Clean Parameters"});
1.333     albertel 6617:     my $start_page=&Apache::loncommon::start_page('Clean Parameters');
                   6618:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Clean');
                   6619:     $r->print(<<ENDOVER);
                   6620: $start_page
                   6621: $breadcrumbs
                   6622: <form method="post" action="/adm/parmset?action=cleanparameters" name="parmform">
                   6623: ENDOVER
                   6624: # Store modified
                   6625: 
                   6626:     &storedata($r,$crs,$dom);
                   6627: 
                   6628: # Read modified data
                   6629: 
                   6630:     my $resourcedata=&readdata($crs,$dom);
                   6631: 
                   6632: # List data
                   6633: 
                   6634:     $r->print('<h3>'.
1.473     amueller 6635:           &mt('These parameters refer to resources that do not exist.').
                   6636:           '</h3>'.
                   6637:           '<input type="submit" value="'.&mt('Delete Selected').'" />'.'<br />'.
                   6638:           '<br />');
1.333     albertel 6639:     $r->print(&Apache::loncommon::start_data_table().
1.473     amueller 6640:           '<tr>'.
                   6641:           '<th>'.&mt('Delete').'</th>'.
                   6642:           '<th>'.&mt('Parameter').'</th>'.
                   6643:           '</tr>');
1.333     albertel 6644:     foreach my $thiskey (sort(keys(%{$resourcedata}))) {
1.560     damieng  6645:         next if (!exists($resourcedata->{$thiskey.'.type'})
                   6646:             && $thiskey=~/\.type$/);
                   6647:         my %data = &parse_key($thiskey);
                   6648:         if (1) { #exists($data{'realm_exists'})
                   6649:             #&& !$data{'realm_exists'}) {
                   6650:             $r->print(&Apache::loncommon::start_data_table_row().
                   6651:                 '<tr>'.
                   6652:                 '<td><input type="checkbox" name="del_'.$thiskey.'" /></td>'              );
                   6653: 
                   6654:             $r->print('<td>');
                   6655:             my $display_value = $resourcedata->{$thiskey};
                   6656:             if (&isdateparm($resourcedata->{$thiskey.'.type'})) {
                   6657:             $display_value =
                   6658:                 &Apache::lonlocal::locallocaltime($display_value);
                   6659:             }
1.470     raeburn  6660:             my $parmitem = &standard_parameter_names($data{'parameter_name'});
                   6661:             $parmitem = &mt($parmitem);
1.560     damieng  6662:             $r->print(&mt('Parameter: "[_1]" with value: "[_2]"',
                   6663:                 $parmitem,$resourcedata->{$thiskey}));
                   6664:             $r->print('<br />');
                   6665:             if ($data{'scope_type'} eq 'all') {
                   6666:                 $r->print(&mt('All users'));
                   6667:             } elsif ($data{'scope_type'} eq 'user') {
                   6668:                 $r->print(&mt('User: [_1]',join(':',@{$data{'scope'}})));
1.581     raeburn  6669:             } elsif ($data{'scope_type'} eq 'secgroup') {
                   6670:                 $r->print(&mt('Group/Section: [_1]',$data{'scope'}));
1.560     damieng  6671:             }
                   6672:             $r->print('<br />');
                   6673:             if ($data{'realm_type'} eq 'all') {
                   6674:                 $r->print(&mt('All Resources'));
                   6675:             } elsif ($data{'realm_type'} eq 'folder') {
                   6676:                 $r->print(&mt('Folder: [_1]'),$data{'realm'});
                   6677:             } elsif ($data{'realm_type'} eq 'symb') {
                   6678:             my ($map,$resid,$url) =
                   6679:                 &Apache::lonnet::decode_symb($data{'realm'});
                   6680:             $r->print(&mt('Resource: [_1]with ID: [_2]in folder [_3]',
                   6681:                         $url.' <br />&nbsp;&nbsp;&nbsp;',
                   6682:                         $resid.' <br />&nbsp;&nbsp;&nbsp;',$map));
                   6683:             }
                   6684:             $r->print(' <br />&nbsp;&nbsp;&nbsp;'.&mt('Part: [_1]',$data{'parameter_part'}));
                   6685:             $r->print('</td></tr>');
                   6686: 
1.473     amueller 6687:         }
1.333     albertel 6688:     }
                   6689:     $r->print(&Apache::loncommon::end_data_table().'<p>'.
1.473     amueller 6690:           '<input type="submit" value="'.&mt('Delete Selected').'" />'.
1.507     www      6691:           '</p></form>');
                   6692:     &endSettingsScreen($r);
                   6693:     $r->print(&Apache::loncommon::end_page());
1.333     albertel 6694: }
                   6695: 
1.563     damieng  6696: # UI to shift all dates (called by dateshift1 action).
                   6697: # Used by overview mode.
                   6698: #
                   6699: # @param {Apache2::RequestRec} $r - the Apache request
1.390     www      6700: sub date_shift_one {
                   6701:     my ($r) = @_;
                   6702:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6703:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  6704:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.594     raeburn  6705:     my $sec = $env{'request.course.sec'};
1.414     droeschl 6706:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'},
1.473     amueller 6707:         text=>"Shifting Dates"});
1.594     raeburn  6708:     my $submit_text = &mt('Shift all dates accordingly');
                   6709:     if ($sec ne '') {
1.595     raeburn  6710:         my @groups;
                   6711:         if ($env{'request.course.groups'} ne '') {
                   6712:             @groups = split(/:/,$env{'request.course.groups'});
                   6713:         }
                   6714:         if (@groups) {
                   6715:             $submit_text = &mt("Shift dates set just for your section/group(s), accordingly");
                   6716:         } else {
                   6717:             $submit_text = &mt("Shift dates set just for your section, accordingly");
                   6718:         }
1.594     raeburn  6719:     }
1.390     www      6720:     my $start_page=&Apache::loncommon::start_page('Shift Dates');
                   6721:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
1.507     www      6722:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6723:     &startSettingsScreen($r,'parmset',$crstype);
1.538     bisitz   6724:     $r->print('<form name="shiftform" method="post" action="">'.
1.390     www      6725:               '<table><tr><td>'.&mt('Currently set date:').'</td><td>'.
                   6726:               &Apache::lonlocal::locallocaltime($env{'form.timebase'}).'</td></tr>'.
                   6727:               '<tr><td>'.&mt('Shifted date:').'</td><td>'.
1.541     bisitz   6728:                     &Apache::lonhtmlcommon::date_setter('shiftform',
1.390     www      6729:                                                         'timeshifted',
                   6730:                                                         $env{'form.timebase'},,
                   6731:                                                         '').
                   6732:               '</td></tr></table>'.
                   6733:               '<input type="hidden" name="action" value="dateshift2" />'.
                   6734:               '<input type="hidden" name="timebase" value="'.$env{'form.timebase'}.'" />'.
1.594     raeburn  6735:               '<input type="submit" value="'.$submit_text.'" /></form>');
1.507     www      6736:     &endSettingsScreen($r);
1.390     www      6737:     $r->print(&Apache::loncommon::end_page());
                   6738: }
                   6739: 
1.563     damieng  6740: # UI to shift all dates (second form).
                   6741: #
                   6742: # @param {Apache2::RequestRec} $r - the Apache request
1.390     www      6743: sub date_shift_two {
                   6744:     my ($r) = @_;
                   6745:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   6746:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.594     raeburn  6747:     my $sec = $env{'request.course.sec'};
1.531     raeburn  6748:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.414     droeschl 6749:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'},
1.473     amueller 6750:         text=>"Shifting Dates"});
1.390     www      6751:     my $start_page=&Apache::loncommon::start_page('Shift Dates');
                   6752:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift');
1.507     www      6753:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  6754:     &startSettingsScreen($r,'parmset',$crstype);
1.390     www      6755:     my $timeshifted=&Apache::lonhtmlcommon::get_date_from_form('timeshifted');
1.594     raeburn  6756:     $r->print('<h2>'.&mt('Shift Dates').'</h2>');
                   6757:     if ($sec ne '') {
1.595     raeburn  6758:         my @groups;
                   6759:         if ($env{'request.course.groups'} ne '') {
                   6760:             @groups = split(/:/,$env{'request.course.groups'});
                   6761:         }
                   6762:         if (@groups) {
                   6763:             $r->print('<p>'.
                   6764:                       &mt("Shift dates set just for your section/group(s), such that [_1] becomes [_2]",
                   6765:                           &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6766:                           &Apache::lonlocal::locallocaltime($timeshifted)).
                   6767:                       '</p>');
                   6768:         } else {
                   6769:             $r->print('<p>'.
                   6770:                       &mt("Shift dates set just for your section, such that [_1] becomes [_2]",
                   6771:                           &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6772:                           &Apache::lonlocal::locallocaltime($timeshifted)).
                   6773:                       '</p>');
                   6774:         }
1.594     raeburn  6775:     } else {
                   6776:         $r->print('<p>'.&mt('Shifting all dates such that [_1] becomes [_2]',
                   6777:                             &Apache::lonlocal::locallocaltime($env{'form.timebase'}),
                   6778:                             &Apache::lonlocal::locallocaltime($timeshifted)).
                   6779:                   '</p>');
                   6780:     }
1.390     www      6781:     my $delta=$timeshifted-$env{'form.timebase'};
1.594     raeburn  6782:     my $numchanges = 0;
                   6783:     my $result = &dateshift($delta,\$numchanges);
                   6784:     if ($result eq 'ok') {
                   6785:         $r->print(
                   6786:             &Apache::lonhtmlcommon::confirm_success(&mt('Completed shifting of [quant,_1,date setting]',
                   6787:                                                     $numchanges)));
                   6788:     } elsif ($result eq 'con_delayed') {
                   6789:         $r->print(
                   6790:             &Apache::lonhtmlcommon::confirm_success(&mt('Queued shifting of [quant,_1,date setting]',
                   6791:                                                         $numchanges)));
                   6792:     } else {
                   6793:         $r->print(
                   6794:             &Apache::lonhtmlcommon::confirm_success(&mt('An error occurred attempting to shift dates'),1));
                   6795:     }
1.543     bisitz   6796:     $r->print(
                   6797:         '<br /><br />'.
                   6798:         &Apache::lonhtmlcommon::actionbox(
                   6799:             ['<a href="/adm/parmset">'.&mt('Content and Problem Settings').'</a>']));
1.507     www      6800:     &endSettingsScreen($r);
1.390     www      6801:     $r->print(&Apache::loncommon::end_page());
                   6802: }
                   6803: 
1.563     damieng  6804: # Returns the different components of a resourcedata key.
                   6805: # Keys: scope_type, scope, realm_type, realm, realm_title,
                   6806: #       realm_exists, parameter_part, parameter_name.
                   6807: # Was used by clean_parameters (which is unused).
                   6808: #
                   6809: # @param {string} $key - the parameter key
                   6810: # @returns {hash}
1.333     albertel 6811: sub parse_key {
                   6812:     my ($key) = @_;
                   6813:     my %data;
                   6814:     my ($middle,$part,$name)=
1.572     damieng  6815:     ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.333     albertel 6816:     $data{'scope_type'} = 'all';
                   6817:     if ($middle=~/^\[(.*)\]/) {
1.560     damieng  6818:         $data{'scope'} = $1;
                   6819:         if ($data{'scope'}=~/^useropt\:($match_username)\:($match_domain)/) {
                   6820:             $data{'scope_type'} = 'user';
                   6821:             $data{'scope'} = [$1,$2];
                   6822:         } else {
1.581     raeburn  6823:             $data{'scope_type'} = 'secgroup';
1.560     damieng  6824:         }
                   6825:         $middle=~s/^\[(.*)\]//;
1.333     albertel 6826:     }
                   6827:     $middle=~s/\.+$//;
                   6828:     $middle=~s/^\.+//;
                   6829:     $data{'realm_type'}='all';
                   6830:     if ($middle=~/^(.+)\_\_\_\(all\)$/) {
1.560     damieng  6831:         $data{'realm'} = $1;
                   6832:         $data{'realm_type'} = 'folder';
                   6833:         $data{'realm_title'} = &Apache::lonnet::gettitle($data{'realm'});
                   6834:         ($data{'realm_exists'}) = &Apache::lonnet::is_on_map($data{'realm'});
1.333     albertel 6835:     } elsif ($middle) {
1.560     damieng  6836:         $data{'realm'} = $middle;
                   6837:         $data{'realm_type'} = 'symb';
                   6838:         $data{'realm_title'} = &Apache::lonnet::gettitle($data{'realm'});
                   6839:         my ($map,$resid,$url) = &Apache::lonnet::decode_symb($data{'realm'});
                   6840:         $data{'realm_exists'} = &Apache::lonnet::symbverify($data{'realm'},$url);
1.333     albertel 6841:     }
1.446     bisitz   6842: 
1.333     albertel 6843:     $data{'parameter_part'} = $part;
                   6844:     $data{'parameter_name'} = $name;
                   6845: 
                   6846:     return %data;
                   6847: }
                   6848: 
1.239     raeburn  6849: 
1.563     damieng  6850: # Calls loncommon::start_page with the "Settings" title.
1.416     jms      6851: sub header {
1.507     www      6852:     return &Apache::loncommon::start_page('Settings');
1.416     jms      6853: }
1.193     albertel 6854: 
                   6855: 
                   6856: 
1.560     damieng  6857: ##################################################
                   6858: # MAIN MENU
                   6859: ##################################################
                   6860: 
1.563     damieng  6861: # Content and problem settings main menu.
                   6862: #
                   6863: # @param {Apache2::RequestRec} $r - the Apache request
                   6864: # @param {boolean} $parm_permission - true if the user has permission to edit the current course or section
1.193     albertel 6865: sub print_main_menu {
                   6866:     my ($r,$parm_permission)=@_;
                   6867:     #
1.414     droeschl 6868:     $r->print(&header());
1.507     www      6869:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Content and Problem Settings'));
1.531     raeburn  6870:     my $crstype = &Apache::loncommon::course_type();
                   6871:     my $lc_crstype = lc($crstype);
                   6872: 
                   6873:     &startSettingsScreen($r,'parmset',$crstype);
1.193     albertel 6874:     $r->print(<<ENDMAINFORMHEAD);
                   6875: <form method="post" enctype="multipart/form-data"
                   6876:       action="/adm/parmset" name="studentform">
                   6877: ENDMAINFORMHEAD
                   6878: #
1.195     albertel 6879:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   6880:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
1.268     albertel 6881:     my $vgr  = &Apache::lonnet::allowed('vgr',$env{'request.course.id'});
1.366     albertel 6882:     my $mgr  = &Apache::lonnet::allowed('mgr',$env{'request.course.id'});
1.520     raeburn  6883:     my $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'});
1.568     raeburn  6884:     my $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'});
                   6885:     my $vpa = &Apache::lonnet::allowed('vpa',$env{'request.course.id'});
1.520     raeburn  6886:     if ((!$dcm) && ($env{'request.course.sec'} ne '')) {
                   6887:         $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'}.
                   6888:                                         '/'.$env{'request.course.sec'});
                   6889:     }
1.568     raeburn  6890:     if ((!$vcb) && ($env{'request.course.sec'} ne '')) {
                   6891:         $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'}.
                   6892:                                         '/'.$env{'request.course.sec'});
                   6893:     }
                   6894:     my (%linktext,%linktitle,%url);
                   6895:     if ($parm_permission->{'edit'}) {
                   6896:         %linktext = (
                   6897:                      newoverview     => 'Edit Resource Parameters - Overview Mode',
                   6898:                      settable        => 'Edit Resource Parameters - Table Mode',
                   6899:                      setoverview     => 'Modify Resource Parameters - Overview Mode',
                   6900:                     );
                   6901:         %linktitle = (
                   6902:                      newoverview     => 'Set/Modify resource parameters in overview mode.',
                   6903:                      settable        => 'Set/Modify resource parameters in table mode.',
                   6904:                      setoverview     => 'Set/Modify existing resource parameters in overview mode.',
                   6905:                      );
                   6906:     } else {
                   6907:         %linktext = (
                   6908:                      newoverview     => 'View Resource Parameters - Overview Mode',
                   6909:                      settable        => 'View Resource Parameters - Table Mode',
                   6910:                      setoverview     => 'View Resource Parameters - Overview Mode',
                   6911:                    );
                   6912:         %linktitle = (
                   6913:                      newoverview     => 'Display resource parameters in overview mode.',
                   6914:                      settable        => 'Display resource parameters in table mode.',
                   6915:                      setoverview     => 'Display existing resource parameters in overview mode.',
                   6916:                      );
                   6917:     }
                   6918:     if ($mgr) {
                   6919:         $linktext{'resettimes'} = 'Reset Student Access Times';
                   6920:         $linktitle{'resettimes'} = "Reset access times for folders/maps, resources or the $lc_crstype.";
                   6921:         $url{'resettimes'} = '/adm/helper/resettimes.helper';
                   6922:     } elsif ($vgr) {
                   6923:         $linktext{'resettimes'} = 'Display Student Access Times',
                   6924:         $linktitle{'resettimes'} = "Display access times for folders/maps, resources or the $lc_crstype.",
                   6925:         $url{'resettimes'} = '/adm/accesstimes';
                   6926:     }
1.193     albertel 6927:     my @menu =
1.507     www      6928:         ( { categorytitle=>"Content Settings for this $crstype",
1.473     amueller 6929:         items => [
                   6930:           { linktext => 'Portfolio Metadata',
                   6931:             url => '/adm/parmset?action=setrestrictmeta',
1.568     raeburn  6932:             permission => $parm_permission->{'setrestrictmeta'},
1.477     raeburn  6933:             linktitle => "Restrict metadata for this $lc_crstype." ,
1.473     amueller 6934:             icon =>'contact-new.png'   ,
                   6935:             },
1.568     raeburn  6936:           { linktext => $linktext{'resettimes'},
                   6937:             url => $url{'resettimes'},
                   6938:             permission => ($vgr || $mgr),
                   6939:             linktitle => $linktitle{'resettimes'},
                   6940:             icon => 'start-here.png',
1.473     amueller 6941:             },
1.520     raeburn  6942:           { linktext => 'Blocking Communication/Resource Access',
                   6943:             url => '/adm/setblock',
1.568     raeburn  6944:             permission => ($vcb || $dcm),
1.520     raeburn  6945:             linktitle => 'Configure blocking of communication/collaboration and access to resources during an exam',
                   6946:             icon => 'comblock.png',
                   6947:             },
1.473     amueller 6948:           { linktext => 'Set Parameter Setting Default Actions',
                   6949:             url => '/adm/parmset?action=setdefaults',
1.568     raeburn  6950:             permission => $parm_permission->{'setdefaults'},
1.473     amueller 6951:             linktitle =>'Set default actions for parameters.'  ,
                   6952:             icon => 'folder-new.png'  ,
                   6953:             }]},
                   6954:       { categorytitle => 'New and Existing Parameter Settings for Resources',
                   6955:         items => [
                   6956:           { linktext => 'Edit Resource Parameters - Helper Mode',
                   6957:             url => '/adm/helper/parameter.helper',
1.568     raeburn  6958:             permission => $parm_permission->{'helper'},
1.473     amueller 6959:             linktitle =>'Set/Modify resource parameters in helper mode.'  ,
                   6960:             icon => 'dialog-information.png'  ,
                   6961:             #help => 'Parameter_Helper',
                   6962:             },
1.568     raeburn  6963:           { linktext => $linktext{'newoverview'},
1.473     amueller 6964:             url => '/adm/parmset?action=newoverview',
1.568     raeburn  6965:             permission => $parm_permission->{'newoverview'},
                   6966:             linktitle => $linktitle{'newoverview'},
                   6967:             icon => 'edit-find.png',
1.473     amueller 6968:             #help => 'Parameter_Overview',
                   6969:             },
1.568     raeburn  6970:           { linktext => $linktext{'settable'},
1.473     amueller 6971:             url => '/adm/parmset?action=settable',
1.568     raeburn  6972:             permission => $parm_permission->{'settable'},
                   6973:             linktitle => $linktitle{'settable'},
                   6974:             icon => 'edit-copy.png',
1.473     amueller 6975:             #help => 'Table_Mode',
                   6976:             }]},
1.417     droeschl 6977:            { categorytitle => 'Existing Parameter Settings for Resources',
1.473     amueller 6978:          items => [
1.570     raeburn  6979:           { linktext => $linktext{'setoverview'},
1.473     amueller 6980:             url => '/adm/parmset?action=setoverview',
1.568     raeburn  6981:             permission => $parm_permission->{'setoverview'},
                   6982:             linktitle => $linktitle{'setoverview'},
                   6983:             icon => 'preferences-desktop-wallpaper.png',
1.473     amueller 6984:             #help => 'Parameter_Overview',
                   6985:             },
                   6986:           { linktext => 'Change Log',
                   6987:             url => '/adm/parmset?action=parameterchangelog',
1.568     raeburn  6988:             permission => $parm_permission->{'parameterchangelog'},
1.477     raeburn  6989:             linktitle =>"View parameter and $lc_crstype blog posting/user notification change log."  ,
1.487     wenzelju 6990:             icon => 'document-properties.png',
1.473     amueller 6991:             }]}
1.193     albertel 6992:           );
1.414     droeschl 6993:     $r->print(&Apache::lonhtmlcommon::generate_menu(@menu));
1.539     raeburn  6994:     $r->print('</form>');
1.507     www      6995:     &endSettingsScreen($r);
1.539     raeburn  6996:     $r->print(&Apache::loncommon::end_page());
1.193     albertel 6997:     return;
                   6998: }
1.414     droeschl 6999: 
1.416     jms      7000: 
                   7001: 
1.560     damieng  7002: ##################################################
                   7003: # PORTFOLIO METADATA
                   7004: ##################################################
                   7005: 
1.563     damieng  7006: # Prints HTML to edit an item of portfolio metadata. The HTML contains several td elements (no tr).
                   7007: # It looks like field titles are not localized.
                   7008: #
                   7009: # @param {Apache2::RequestRec} $r - the Apache request
                   7010: # @param {string} $field_name - metadata field name
                   7011: # @param {string} $field_text - metadata field title, in English unless manually added
                   7012: # @param {boolean} $added_flag - true if the field was manually added
1.252     banghart 7013: sub output_row {
1.347     banghart 7014:     my ($r, $field_name, $field_text, $added_flag) = @_;
1.252     banghart 7015:     my $output;
1.263     banghart 7016:     my $options=$env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.options'};
                   7017:     my $values=$env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.values'};
1.337     banghart 7018:     if (!defined($options)) {
1.254     banghart 7019:         $options = 'active,stuadd';
1.261     banghart 7020:         $values = '';
1.252     banghart 7021:     }
1.337     banghart 7022:     if (!($options =~ /deleted/)) {
                   7023:         my @options= ( ['active', 'Show to student'],
1.418     schafran 7024:                     ['stuadd', 'Provide text area for students to type metadata'],
1.351     banghart 7025:                     ['choices','Provide choices for students to select from']);
1.473     amueller 7026: #           ['onlyone','Student may select only one choice']);
1.337     banghart 7027:         if ($added_flag) {
                   7028:             push @options,['deleted', 'Delete Metadata Field'];
                   7029:         }
1.351     banghart 7030:        $output = &Apache::loncommon::start_data_table_row();
1.451     bisitz   7031:         $output .= '<td><strong>'.$field_text.':</strong></td>';
1.351     banghart 7032:         $output .= &Apache::loncommon::end_data_table_row();
1.337     banghart 7033:         foreach my $opt (@options) {
1.560     damieng  7034:             my $checked = ($options =~ m/$opt->[0]/) ? ' checked="checked" ' : '' ;
                   7035:             $output .= &Apache::loncommon::continue_data_table_row();
                   7036:             $output .= '<td>'.('&nbsp;' x 5).'<label>
                   7037:                     <input type="checkbox" name="'.
                   7038:                     $field_name.'_'.$opt->[0].'" value="yes"'.$checked.' />'.
                   7039:                     &mt($opt->[1]).'</label></td>';
                   7040:             $output .= &Apache::loncommon::end_data_table_row();
                   7041:         }
1.351     banghart 7042:         $output .= &Apache::loncommon::continue_data_table_row();
1.451     bisitz   7043:         $output .= '<td>'.('&nbsp;' x 10).'<input name="'.$field_name.'_values" type="text" value="'.$values.'" size="80" /></td>';
1.351     banghart 7044:         $output .= &Apache::loncommon::end_data_table_row();
                   7045:         my $multiple_checked;
                   7046:         my $single_checked;
                   7047:         if ($options =~ m/onlyone/) {
1.422     bisitz   7048:             $multiple_checked = '';
1.423     bisitz   7049:             $single_checked = ' checked="checked"';
1.351     banghart 7050:         } else {
1.423     bisitz   7051:             $multiple_checked = ' checked="checked"';
1.422     bisitz   7052:             $single_checked = '';
1.351     banghart 7053:         }
1.560     damieng  7054:         $output .= &Apache::loncommon::continue_data_table_row();
                   7055:         $output .= '<td>'.('&nbsp;' x 10).'
                   7056:                     <input type="radio" name="'.$field_name.'_onlyone" value="multiple"'.$multiple_checked .' />
                   7057:                     '.&mt('Student may select multiple choices from list').'</td>';
                   7058:         $output .= &Apache::loncommon::end_data_table_row();
                   7059:         $output .= &Apache::loncommon::continue_data_table_row();
                   7060:         $output .= '<td>'.('&nbsp;' x 10).'
                   7061:                     <input type="radio" name="'.$field_name.'_onlyone"  value="single"'.$single_checked.' />
                   7062:                     '.&mt('Student may select only one choice from list').'</td>';
                   7063:         $output .= &Apache::loncommon::end_data_table_row();
1.252     banghart 7064:     }
                   7065:     return ($output);
                   7066: }
1.416     jms      7067: 
                   7068: 
1.560     damieng  7069: # UI to order portfolio metadata fields.
1.563     damieng  7070: # Currently useless because addmetafield does not work.
                   7071: #
                   7072: # @param {Apache2::RequestRec} $r - the Apache request
1.340     banghart 7073: sub order_meta_fields {
                   7074:     my ($r)=@_;
                   7075:     my $idx = 1;
                   7076:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7077:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7078:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};;
1.341     banghart 7079:     $r->print(&Apache::loncommon::start_page('Order Metadata Fields'));
1.560     damieng  7080:     &Apache::lonhtmlcommon::add_breadcrumb(
                   7081:         {href=>'/adm/parmset?action=addmetadata',
1.473     amueller 7082:         text=>"Add Metadata Field"});
1.560     damieng  7083:     &Apache::lonhtmlcommon::add_breadcrumb(
                   7084:         {href=>"/adm/parmset?action=setrestrictmeta",
                   7085:         text=>"Restrict Metadata"},
                   7086:         {text=>"Order Metadata"});
1.345     banghart 7087:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Order Metadata'));
1.531     raeburn  7088:     &startSettingsScreen($r,'parmset',$crstype);
1.340     banghart 7089:     if ($env{'form.storeorder'}) {
                   7090:         my $newpos = $env{'form.newpos'} - 1;
                   7091:         my $currentpos = $env{'form.currentpos'} - 1;
                   7092:         my @neworder = ();
1.548     raeburn  7093:         my @oldorder = split(/,/,$env{'course.'.$env{'request.course.id'}.'.metadata.addedorder'});
1.340     banghart 7094:         my $i;
1.341     banghart 7095:         if ($newpos > $currentpos) {
1.340     banghart 7096:         # moving stuff up
                   7097:             for ($i=0;$i<$currentpos;$i++) {
1.560     damieng  7098:                 $neworder[$i]=$oldorder[$i];
1.340     banghart 7099:             }
                   7100:             for ($i=$currentpos;$i<$newpos;$i++) {
1.560     damieng  7101:                 $neworder[$i]=$oldorder[$i+1];
1.340     banghart 7102:             }
                   7103:             $neworder[$newpos]=$oldorder[$currentpos];
                   7104:             for ($i=$newpos+1;$i<=$#oldorder;$i++) {
1.560     damieng  7105:                 $neworder[$i]=$oldorder[$i];
1.340     banghart 7106:             }
                   7107:         } else {
                   7108:         # moving stuff down
1.473     amueller 7109:             for ($i=0;$i<$newpos;$i++) {
                   7110:                 $neworder[$i]=$oldorder[$i];
                   7111:             }
                   7112:             $neworder[$newpos]=$oldorder[$currentpos];
                   7113:             for ($i=$newpos+1;$i<$currentpos+1;$i++) {
                   7114:                 $neworder[$i]=$oldorder[$i-1];
                   7115:             }
                   7116:             for ($i=$currentpos+1;$i<=$#oldorder;$i++) {
                   7117:                 $neworder[$i]=$oldorder[$i];
                   7118:             }
1.340     banghart 7119:         }
1.560     damieng  7120:         my $ordered_fields = join ",", @neworder;
1.343     banghart 7121:         my $put_result = &Apache::lonnet::put('environment',
1.560     damieng  7122:                         {'metadata.addedorder'=>$ordered_fields},$dom,$crs);
                   7123:         &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.metadata.addedorder' => $ordered_fields});
1.340     banghart 7124:     }
1.357     raeburn  7125:     my $fields = &get_added_meta_fieldnames($env{'request.course.id'});
1.341     banghart 7126:     my $ordered_fields;
1.548     raeburn  7127:     my @fields_in_order = split(/,/,$env{'course.'.$env{'request.course.id'}.'.metadata.addedorder'});
1.340     banghart 7128:     if (!@fields_in_order) {
                   7129:         # no order found, pick sorted order then create metadata.addedorder key.
1.548     raeburn  7130:         foreach my $key (sort(keys(%$fields))) {
1.340     banghart 7131:             push @fields_in_order, $key;
1.341     banghart 7132:             $ordered_fields = join ",", @fields_in_order;
1.340     banghart 7133:         }
1.341     banghart 7134:         my $put_result = &Apache::lonnet::put('environment',
1.446     bisitz   7135:                             {'metadata.addedorder'=>$ordered_fields},$dom,$crs);
                   7136:     }
1.340     banghart 7137:     $r->print('<table>');
                   7138:     my $num_fields = scalar(@fields_in_order);
                   7139:     foreach my $key (@fields_in_order) {
                   7140:         $r->print('<tr><td>');
                   7141:         $r->print('<form method="post" action="">');
1.537     bisitz   7142:         $r->print('<select name="newpos" onchange="this.form.submit()">');
1.340     banghart 7143:         for (my $i = 1;$i le $num_fields;$i ++) {
                   7144:             if ($i eq $idx) {
                   7145:                 $r->print('<option value="'.$i.'"  SELECTED>('.$i.')</option>');
                   7146:             } else {
                   7147:                 $r->print('<option value="'.$i.'">'.$i.'</option>');
                   7148:             }
                   7149:         }
                   7150:         $r->print('</select></td><td>');
                   7151:         $r->print('<input type="hidden" name="currentpos" value="'.$idx.'" />');
                   7152:         $r->print('<input type="hidden" name="storeorder" value="true" />');
                   7153:         $r->print('</form>');
                   7154:         $r->print($$fields{$key}.'</td></tr>');
                   7155:         $idx ++;
                   7156:     }
                   7157:     $r->print('</table>');
1.507     www      7158:     &endSettingsScreen($r);
1.340     banghart 7159:     return 'ok';
                   7160: }
1.416     jms      7161: 
                   7162: 
1.563     damieng  7163: # Returns HTML with a Continue button redirecting to the initial portfolio metadata screen.
                   7164: # @returns {string}
1.359     banghart 7165: sub continue {
                   7166:     my $output;
                   7167:     $output .= '<form action="" method="post">';
                   7168:     $output .= '<input type="hidden" name="action" value="setrestrictmeta" />';
1.586     raeburn  7169:     $output .= '<input type="submit" value="'.&mt('Continue').'" />';
1.359     banghart 7170:     return ($output);
                   7171: }
1.416     jms      7172: 
                   7173: 
1.563     damieng  7174: # UI to add a metadata field.
                   7175: # Currenly does not work because of an HTML error (the field is not visible).
                   7176: #
                   7177: # @param {Apache2::RequestRec} $r - the Apache request
1.334     banghart 7178: sub addmetafield {
                   7179:     my ($r)=@_;
1.414     droeschl 7180:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=addmetadata',
1.473     amueller 7181:         text=>"Add Metadata Field"});
1.334     banghart 7182:     $r->print(&Apache::loncommon::start_page('Add Metadata Field'));
                   7183:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Add Metadata Field'));
1.335     banghart 7184:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7185:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7186:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   7187:     &startSettingsScreen($r,'parmset',$crstype);
1.339     banghart 7188:     if (exists($env{'form.undelete'})) {
1.358     banghart 7189:         my @meta_fields = &Apache::loncommon::get_env_multiple('form.undeletefield');
1.339     banghart 7190:         foreach my $meta_field(@meta_fields) {
                   7191:             my $options = $env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.options'};
                   7192:             $options =~ s/deleted//;
                   7193:             $options =~ s/,,/,/;
                   7194:             my $put_result = &Apache::lonnet::put('environment',
                   7195:                                         {'metadata.'.$meta_field.'.options'=>$options},$dom,$crs);
1.446     bisitz   7196: 
1.586     raeburn  7197:             $r->print(&mt('Undeleted Metadata Field [_1] with result [_2]',
                   7198:                           '<strong>'.$env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.added'}.
                   7199:                           '</strong>',$put_result).
                   7200:                       '<br />');
1.339     banghart 7201:         }
1.359     banghart 7202:         $r->print(&continue());
1.339     banghart 7203:     } elsif (exists($env{'form.fieldname'})) {
1.335     banghart 7204:         my $meta_field = $env{'form.fieldname'};
                   7205:         my $display_field = $env{'form.fieldname'};
                   7206:         $meta_field =~ s/\W/_/g;
1.338     banghart 7207:         $meta_field =~ tr/A-Z/a-z/;
1.335     banghart 7208:         my $put_result = &Apache::lonnet::put('environment',
                   7209:                             {'metadata.'.$meta_field.'.values'=>"",
                   7210:                              'metadata.'.$meta_field.'.added'=>"$display_field",
                   7211:                              'metadata.'.$meta_field.'.options'=>""},$dom,$crs);
1.586     raeburn  7212:         $r->print(&mt('Added new Metadata Field [_1] with result [_2]',
                   7213:                       '<strong>'.$env{'form.fieldname'}.'</strong>',$put_result).
                   7214:                   '<br />');
1.359     banghart 7215:         $r->print(&continue());
1.335     banghart 7216:     } else {
1.357     raeburn  7217:         my $fields = &get_deleted_meta_fieldnames($env{'request.course.id'});
1.339     banghart 7218:         if ($fields) {
1.586     raeburn  7219:             $r->print(&mt('You may undelete previously deleted fields.').
                   7220:                       '<br />'.
                   7221:                       &mt('Check those you wish to undelete and click Undelete.').
                   7222:                       '<br />');
1.339     banghart 7223:             $r->print('<form method="post" action="">');
                   7224:             foreach my $key(keys(%$fields)) {
1.581     raeburn  7225:                 $r->print('<label><input type="checkbox" name="undeletefield" value="'.$key.'" />'.$$fields{$key}.'</label><br /');
1.339     banghart 7226:             }
1.586     raeburn  7227:             $r->print('<input type="submit" name="undelete" value="'.&mt('Undelete').'" />');
1.339     banghart 7228:             $r->print('</form>');
                   7229:         }
1.586     raeburn  7230:         $r->print('<hr />'.
                   7231:                   &mt('[_1]Or[_2] you may enter a new metadata field name.',
                   7232:                       '<strong>','</strong>').
1.581     raeburn  7233:                   '<form method="post" action="/adm/parmset?action=addmetadata">');
1.335     banghart 7234:         $r->print('<input type="text" name="fieldname" /><br />');
1.586     raeburn  7235:         $r->print('<input type="submit" value="'.&mt('Add Metadata Field').'" />');
1.581     raeburn  7236:         $r->print('</form>');
1.334     banghart 7237:     }
1.507     www      7238:     &endSettingsScreen($r);
1.334     banghart 7239: }
1.416     jms      7240: 
                   7241: 
                   7242: 
1.560     damieng  7243: # Display or save portfolio metadata.
1.563     damieng  7244: #
                   7245: # @param {Apache2::RequestRec} $r - the Apache request
1.259     banghart 7246: sub setrestrictmeta {
1.240     banghart 7247:     my ($r)=@_;
1.242     banghart 7248:     my $next_meta;
1.244     banghart 7249:     my $output;
1.245     banghart 7250:     my $item_num;
1.246     banghart 7251:     my $put_result;
1.414     droeschl 7252:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setrestrictmeta',
1.473     amueller 7253:         text=>"Restrict Metadata"});
1.280     albertel 7254:     $r->print(&Apache::loncommon::start_page('Restrict Metadata'));
1.298     albertel 7255:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Restrict Metadata'));
1.240     banghart 7256:     my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7257:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
1.531     raeburn  7258:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
                   7259:     &startSettingsScreen($r,'parmset',$crstype);
1.259     banghart 7260:     my $key_base = $env{'course.'.$env{'request.course.id'}.'.'};
1.252     banghart 7261:     my $save_field = '';
1.586     raeburn  7262:     my %lt = &Apache::lonlocal::texthash(
                   7263:                                            addm => 'Add Metadata Field',
                   7264:                                            ordm => 'Order Metadata Fields',
                   7265:                                            save => 'Save',
                   7266:                                         );
1.259     banghart 7267:     if ($env{'form.restrictmeta'}) {
1.254     banghart 7268:         foreach my $field (sort(keys(%env))) {
1.252     banghart 7269:             if ($field=~m/^form.(.+)_(.+)$/) {
1.254     banghart 7270:                 my $options;
1.252     banghart 7271:                 my $meta_field = $1;
                   7272:                 my $meta_key = $2;
1.253     banghart 7273:                 if ($save_field ne $meta_field) {
1.252     banghart 7274:                     $save_field = $meta_field;
1.473     amueller 7275:                     if ($env{'form.'.$meta_field.'_stuadd'}) {
                   7276:                         $options.='stuadd,';
                   7277:                     }
                   7278:                     if ($env{'form.'.$meta_field.'_choices'}) {
                   7279:                         $options.='choices,';
                   7280:                     }
                   7281:                     if ($env{'form.'.$meta_field.'_onlyone'} eq 'single') {
                   7282:                         $options.='onlyone,';
                   7283:                     }
                   7284:                     if ($env{'form.'.$meta_field.'_active'}) {
                   7285:                         $options.='active,';
                   7286:                     }
                   7287:                     if ($env{'form.'.$meta_field.'_deleted'}) {
                   7288:                         $options.='deleted,';
                   7289:                     }
1.259     banghart 7290:                     my $name = $save_field;
1.560     damieng  7291:                     $put_result = &Apache::lonnet::put('environment',
                   7292:                         {'metadata.'.$meta_field.'.options'=>$options,
                   7293:                         'metadata.'.$meta_field.'.values'=>$env{'form.'.$meta_field.'_values'},
                   7294:                         },$dom,$crs);
1.252     banghart 7295:                 }
                   7296:             }
                   7297:         }
                   7298:     }
1.296     albertel 7299:     &Apache::lonnet::coursedescription($env{'request.course.id'},
1.473     amueller 7300:                        {'freshen_cache' => 1});
1.335     banghart 7301:     # Get the default metadata fields
1.258     albertel 7302:     my %metadata_fields = &Apache::lonmeta::fieldnames('portfolio');
1.335     banghart 7303:     # Now get possible added metadata fields
1.357     raeburn  7304:     my $added_metadata_fields = &get_added_meta_fieldnames($env{'request.course.id'});
1.347     banghart 7305:     $output .= &Apache::loncommon::start_data_table();
1.258     albertel 7306:     foreach my $field (sort(keys(%metadata_fields))) {
1.265     banghart 7307:         if ($field ne 'courserestricted') {
1.586     raeburn  7308:             $output.= &output_row($r,$field,$metadata_fields{$field});
1.560     damieng  7309:         }
1.255     banghart 7310:     }
1.351     banghart 7311:     my $buttons = (<<ENDButtons);
1.586     raeburn  7312:         <input type="submit" name="restrictmeta" value="$lt{'save'}" />
1.351     banghart 7313:         </form><br />
                   7314:         <form method="post" action="/adm/parmset?action=addmetadata" name="form1">
1.586     raeburn  7315:         <input type="submit" name="restrictmeta" value="$lt{'addm'}" />
1.351     banghart 7316:         </form>
                   7317:         <br />
                   7318:         <form method="post" action="/adm/parmset?action=ordermetadata" name="form2">
1.586     raeburn  7319:         <input type="submit" name="restrictmeta" value="$lt{'ordm'}" />
1.351     banghart 7320: ENDButtons
1.337     banghart 7321:     my $added_flag = 1;
1.335     banghart 7322:     foreach my $field (sort(keys(%$added_metadata_fields))) {
1.586     raeburn  7323:         $output.= &output_row($r,$field,$$added_metadata_fields{$field},$added_flag);
1.335     banghart 7324:     }
1.347     banghart 7325:     $output .= &Apache::loncommon::end_data_table();
1.446     bisitz   7326:     $r->print(<<ENDenv);
1.259     banghart 7327:         <form method="post" action="/adm/parmset?action=setrestrictmeta" name="form">
1.244     banghart 7328:         $output
1.351     banghart 7329:         $buttons
1.340     banghart 7330:         </form>
1.244     banghart 7331: ENDenv
1.507     www      7332:     &endSettingsScreen($r);
1.280     albertel 7333:     $r->print(&Apache::loncommon::end_page());
1.240     banghart 7334:     return 'ok';
                   7335: }
1.416     jms      7336: 
                   7337: 
1.563     damieng  7338: # Returns metadata fields that have been manually added.
                   7339: #
                   7340: # @param {string} $cid - course id
                   7341: # @returns {hash reference} - hash field name -> field title (not localized)
1.335     banghart 7342: sub get_added_meta_fieldnames {
1.357     raeburn  7343:     my ($cid) = @_;
1.335     banghart 7344:     my %fields;
                   7345:     foreach my $key(%env) {
1.357     raeburn  7346:         if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) {
1.335     banghart 7347:             my $field_name = $1;
                   7348:             my ($display_field_name) = $env{$key};
                   7349:             $fields{$field_name} = $display_field_name;
                   7350:         }
                   7351:     }
                   7352:     return \%fields;
                   7353: }
1.416     jms      7354: 
                   7355: 
1.563     damieng  7356: # Returns metadata fields that have been manually added and deleted.
                   7357: #
                   7358: # @param {string} $cid - course id
                   7359: # @returns {hash reference} - hash field name -> field title (not localized)
1.339     banghart 7360: sub get_deleted_meta_fieldnames {
1.357     raeburn  7361:     my ($cid) = @_;
1.339     banghart 7362:     my %fields;
                   7363:     foreach my $key(%env) {
1.357     raeburn  7364:         if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) {
1.339     banghart 7365:             my $field_name = $1;
                   7366:             if ($env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.options'} =~ m/deleted/) {
                   7367:                 my ($display_field_name) = $env{$key};
                   7368:                 $fields{$field_name} = $display_field_name;
                   7369:             }
                   7370:         }
                   7371:     }
                   7372:     return \%fields;
                   7373: }
1.560     damieng  7374: 
                   7375: 
                   7376: ##################################################
                   7377: # PARAMETER SETTINGS DEFAULT ACTIONS
                   7378: ##################################################
                   7379: 
                   7380: # UI to change parameter setting default actions
1.563     damieng  7381: #
                   7382: # @param {Apache2::RequestRec} $r - the Apache request
1.220     www      7383: sub defaultsetter {
1.280     albertel 7384:     my ($r) = @_;
                   7385: 
1.414     droeschl 7386:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setdefaults',
1.473     amueller 7387:         text=>"Set Defaults"});
1.531     raeburn  7388:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7389:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                   7390:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.446     bisitz   7391:     my $start_page =
1.531     raeburn  7392:         &Apache::loncommon::start_page('Parameter Setting Default Actions');
1.298     albertel 7393:     my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Defaults');
1.507     www      7394:     $r->print($start_page.$breadcrumbs);
1.531     raeburn  7395:     &startSettingsScreen($r,'parmset',$crstype);
1.507     www      7396:     $r->print('<form method="post" action="/adm/parmset?action=setdefaults" name="defaultform">');
1.280     albertel 7397: 
1.221     www      7398:     my @ids=();
                   7399:     my %typep=();
                   7400:     my %keyp=();
                   7401:     my %allparms=();
                   7402:     my %allparts=();
                   7403:     my %allmaps=();
                   7404:     my %mapp=();
                   7405:     my %symbp=();
                   7406:     my %maptitles=();
                   7407:     my %uris=();
                   7408:     my %keyorder=&standardkeyorder();
                   7409:     my %defkeytype=();
                   7410: 
1.446     bisitz   7411:     &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps,
1.473     amueller 7412:                 \%mapp, \%symbp,\%maptitles,\%uris,
                   7413:                 \%keyorder,\%defkeytype);
1.224     www      7414:     if ($env{'form.storerules'}) {
1.560     damieng  7415:         my %newrules=();
                   7416:         my @delrules=();
                   7417:         my %triggers=();
                   7418:         foreach my $key (keys(%env)) {
1.225     albertel 7419:             if ($key=~/^form\.(\w+)\_action$/) {
1.560     damieng  7420:                 my $tempkey=$1;
                   7421:                 my $action=$env{$key};
1.226     www      7422:                 if ($action) {
1.560     damieng  7423:                     $newrules{$tempkey.'_action'}=$action;
                   7424:                     if ($action ne 'default') {
                   7425:                         my ($whichaction,$whichparm)=($action=~/^(.*\_)([^\_]+)$/);
                   7426:                         $triggers{$whichparm}.=$tempkey.':';
                   7427:                     }
                   7428:                     $newrules{$tempkey.'_type'}=$defkeytype{$tempkey};
                   7429:                     if (&isdateparm($defkeytype{$tempkey})) {
                   7430:                         $newrules{$tempkey.'_days'}=$env{'form.'.$tempkey.'_days'};
                   7431:                         $newrules{$tempkey.'_hours'}=$env{'form.'.$tempkey.'_hours'};
                   7432:                         $newrules{$tempkey.'_min'}=$env{'form.'.$tempkey.'_min'};
                   7433:                         $newrules{$tempkey.'_sec'}=$env{'form.'.$tempkey.'_sec'};
                   7434:                     } else {
                   7435:                         $newrules{$tempkey.'_value'}=$env{'form.'.$tempkey.'_value'};
                   7436:                         $newrules{$tempkey.'_triggervalue'}=$env{'form.'.$tempkey.'_triggervalue'};
                   7437:                     }
                   7438:                 } else {
                   7439:                     push(@delrules,$tempkey.'_action');
                   7440:                     push(@delrules,$tempkey.'_type');
                   7441:                     push(@delrules,$tempkey.'_hours');
                   7442:                     push(@delrules,$tempkey.'_min');
                   7443:                     push(@delrules,$tempkey.'_sec');
                   7444:                     push(@delrules,$tempkey.'_value');
                   7445:                 }
1.473     amueller 7446:             }
                   7447:         }
1.560     damieng  7448:         foreach my $key (keys(%allparms)) {
                   7449:             $newrules{$key.'_triggers'}=$triggers{$key};
1.473     amueller 7450:         }
1.560     damieng  7451:         &Apache::lonnet::put('parmdefactions',\%newrules,$cdom,$cnum);
                   7452:         &Apache::lonnet::del('parmdefactions',\@delrules,$cdom,$cnum);
                   7453:         &resetrulescache();
1.224     www      7454:     }
1.227     www      7455:     my %lt=&Apache::lonlocal::texthash('days' => 'Days',
1.473     amueller 7456:                        'hours' => 'Hours',
                   7457:                        'min' => 'Minutes',
                   7458:                        'sec' => 'Seconds',
                   7459:                        'yes' => 'Yes',
                   7460:                        'no' => 'No');
1.222     www      7461:     my @standardoptions=('','default');
                   7462:     my @standarddisplay=('',&mt('Default value when manually setting'));
                   7463:     my @dateoptions=('','default');
                   7464:     my @datedisplay=('',&mt('Default value when manually setting'));
                   7465:     foreach my $tempkey (&keysindisplayorder(\%allparms,\%keyorder)) {
1.560     damieng  7466:         unless ($tempkey) { next; }
                   7467:         push @standardoptions,'when_setting_'.$tempkey;
                   7468:         push @standarddisplay,&mt('Automatically set when setting ').$tempkey;
                   7469:         if (&isdateparm($defkeytype{$tempkey})) {
                   7470:             push @dateoptions,'later_than_'.$tempkey;
                   7471:             push @datedisplay,&mt('Automatically set later than ').$tempkey;
                   7472:             push @dateoptions,'earlier_than_'.$tempkey;
                   7473:             push @datedisplay,&mt('Automatically set earlier than ').$tempkey;
                   7474:         }
1.222     www      7475:     }
1.563     damieng  7476:     $r->print(&mt('Manual setting rules apply to all interfaces.').'<br />'.
                   7477:         &mt('Automatic setting rules apply to table mode interfaces only.'));
1.318     albertel 7478:     $r->print("\n".&Apache::loncommon::start_data_table().
1.473     amueller 7479:           &Apache::loncommon::start_data_table_header_row().
                   7480:           "<th>".&mt('Rule for parameter').'</th><th>'.
                   7481:           &mt('Action').'</th><th>'.&mt('Value').'</th>'.
                   7482:           &Apache::loncommon::end_data_table_header_row());
1.221     www      7483:     foreach my $tempkey (&keysindisplayorder(\%allparms,\%keyorder)) {
1.560     damieng  7484:         unless ($tempkey) { next; }
                   7485:         $r->print("\n".&Apache::loncommon::start_data_table_row().
                   7486:             "<td>".$allparms{$tempkey}."\n<br />(".$tempkey.')</td><td>');
                   7487:         my $action=&rulescache($tempkey.'_action');
                   7488:         $r->print('<select name="'.$tempkey.'_action">');
                   7489:         if (&isdateparm($defkeytype{$tempkey})) {
                   7490:             for (my $i=0;$i<=$#dateoptions;$i++) {
                   7491:             if ($dateoptions[$i]=~/\_$tempkey$/) { next; }
                   7492:             $r->print("\n<option value='$dateoptions[$i]'".
                   7493:                 ($dateoptions[$i] eq $action?' selected="selected"':'').
                   7494:                 ">$datedisplay[$i]</option>");
                   7495:             }
                   7496:         } else {
                   7497:             for (my $i=0;$i<=$#standardoptions;$i++) {
                   7498:             if ($standardoptions[$i]=~/\_$tempkey$/) { next; }
                   7499:             $r->print("\n<option value='$standardoptions[$i]'".
                   7500:                 ($standardoptions[$i] eq $action?' selected="selected"':'').
                   7501:                 ">$standarddisplay[$i]</option>");
                   7502:             }
1.473     amueller 7503:         }
1.560     damieng  7504:         $r->print('</select>');
                   7505:         unless (&isdateparm($defkeytype{$tempkey})) {
                   7506:             $r->print("\n<br />".&mt('Triggering value(s) of other parameter (optional, comma-separated):').
                   7507:                 '<input type="text" size="20" name="'.$tempkey.'_triggervalue" value="'.&rulescache($tempkey.'_triggervalue').'" />');
1.473     amueller 7508:         }
1.560     damieng  7509:         $r->print("\n</td><td>\n");
1.222     www      7510: 
1.221     www      7511:         if (&isdateparm($defkeytype{$tempkey})) {
1.560     damieng  7512:             my $days=&rulescache($tempkey.'_days');
                   7513:             my $hours=&rulescache($tempkey.'_hours');
                   7514:             my $min=&rulescache($tempkey.'_min');
                   7515:             my $sec=&rulescache($tempkey.'_sec');
                   7516:             $r->print(<<ENDINPUTDATE);
                   7517:     <input name="$tempkey\_days" type="text" size="4" value="$days" />$lt{'days'}<br />
                   7518:     <input name="$tempkey\_hours" type="text" size="4" value="$hours" />$lt{'hours'}<br />
                   7519:     <input name="$tempkey\_min" type="text" size="4" value="$min" />$lt{'min'}<br />
                   7520:     <input name="$tempkey\_sec" type="text" size="4" value="$sec" />$lt{'sec'}
1.564     raeburn  7521: ENDINPUTDATE
1.560     damieng  7522:         } elsif ($defkeytype{$tempkey} eq 'string_yesno') {
                   7523:                 my $yeschecked='';
                   7524:                 my $nochecked='';
                   7525:                 if (&rulescache($tempkey.'_value') eq 'yes') { $yeschecked=' checked="checked"'; }
                   7526:                 if (&rulescache($tempkey.'_value') eq 'no') { $nochecked=' checked="checked"'; }
                   7527: 
                   7528:             $r->print(<<ENDYESNO);
                   7529:     <label><input type="radio" name="$tempkey\_value" value="yes"$yeschecked /> $lt{'yes'}</label><br />
                   7530:     <label><input type="radio" name="$tempkey\_value" value="no"$nochecked /> $lt{'no'}</label>
1.564     raeburn  7531: ENDYESNO
1.221     www      7532:         } else {
1.560     damieng  7533:             $r->print('<input type="text" size="20" name="'.$tempkey.'_value" value="'.&rulescache($tempkey.'_value').'" />');
                   7534:         }
1.318     albertel 7535:         $r->print('</td>'.&Apache::loncommon::end_data_table_row());
1.221     www      7536:     }
1.318     albertel 7537:     $r->print(&Apache::loncommon::end_data_table().
1.473     amueller 7538:           "\n".'<input type="submit" name="storerules" value="'.
1.507     www      7539:           &mt('Save').'" /></form>'."\n");
                   7540:     &endSettingsScreen($r);
                   7541:     $r->print(&Apache::loncommon::end_page());
1.220     www      7542:     return;
                   7543: }
1.193     albertel 7544: 
1.560     damieng  7545: ##################################################
                   7546: # PARAMETER CHANGES LOG
                   7547: ##################################################
                   7548: 
1.563     damieng  7549: # Returns some info for a parameter log entry.
                   7550: # Returned entries:
                   7551: # $realm - HTML title for the parameter level and resource
                   7552: # $section - parameter section
                   7553: # $name - parameter name
                   7554: # $part - parameter part
                   7555: # $what - $part.'.'.$name
                   7556: # $middle - resource symb ?
                   7557: # $uname - user name (same as given)
                   7558: # $udom - user domain (same as given)
                   7559: # $issection - section or group name
                   7560: # $realmdescription - title for the parameter level and resource (without using HTML)
                   7561: #
                   7562: # @param {string} $key - parameter log key
                   7563: # @param {string} $uname - user name
                   7564: # @param {string} $udom - user domain
                   7565: # @param {boolean} $typeflag - .type log entry
                   7566: # @returns {Array}
1.290     www      7567: sub components {
1.581     raeburn  7568:     my ($key,$uname,$udom,$typeflag)=@_;
1.330     albertel 7569: 
                   7570:     if ($typeflag) {
1.560     damieng  7571:         $key=~s/\.type$//;
1.290     www      7572:     }
1.330     albertel 7573: 
                   7574:     my ($middle,$part,$name)=
1.572     damieng  7575:         ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/);
1.291     www      7576:     my $issection;
1.330     albertel 7577: 
1.290     www      7578:     my $section=&mt('All Students');
                   7579:     if ($middle=~/^\[(.*)\]/) {
1.560     damieng  7580:         $issection=$1;
                   7581:         $section=&mt('Group/Section').': '.$issection;
                   7582:         $middle=~s/^\[(.*)\]//;
1.290     www      7583:     }
                   7584:     $middle=~s/\.+$//;
                   7585:     $middle=~s/^\.+//;
1.291     www      7586:     if ($uname) {
1.560     damieng  7587:         $section=&mt('User').": ".&Apache::loncommon::plainname($uname,$udom);
                   7588:         $issection='';
1.291     www      7589:     }
1.316     albertel 7590:     my $realm='<span class="LC_parm_scope_all">'.&mt('All Resources').'</span>';
1.446     bisitz   7591:     my $realmdescription=&mt('all resources');
1.556     raeburn  7592:     if ($middle=~/^(.+)\_\_\_\((all|rec)\)$/) {
                   7593:         my $mapurl = $1;
                   7594:         my $maplevel = $2;
                   7595:         my $leveltitle = &mt('Folder/Map');
                   7596:         if ($maplevel eq 'rec') {
                   7597:             $leveltitle = &mt('Recursive');
                   7598:         }
1.560     damieng  7599:         $realm='<span class="LC_parm_scope_folder">'.$leveltitle.
                   7600:             ': '.&Apache::lonnet::gettitle($mapurl).' <span class="LC_parm_folder"><br />('.
                   7601:             $mapurl.')</span></span>';
                   7602:         $realmdescription=&mt('folder').' '.&Apache::lonnet::gettitle($mapurl);
                   7603:     } elsif ($middle) {
                   7604:         my ($map,$id,$url)=&Apache::lonnet::decode_symb($middle);
                   7605:         $realm='<span class="LC_parm_scope_resource">'.&mt('Resource').
                   7606:             ': '.&Apache::lonnet::gettitle($middle).' <br /><span class="LC_parm_symb">('.$url.
                   7607:             ' in '.$map.' id: '.$id.')</span></span>';
                   7608:         $realmdescription=&mt('resource').' '.&Apache::lonnet::gettitle($middle);
1.290     www      7609:     }
1.291     www      7610:     my $what=$part.'.'.$name;
1.330     albertel 7611:     return ($realm,$section,$name,$part,
1.473     amueller 7612:         $what,$middle,$uname,$udom,$issection,$realmdescription);
1.290     www      7613: }
1.293     www      7614: 
1.563     damieng  7615: my %standard_parms; # hash parameter name -> parameter title (not localized)
                   7616: my %standard_parms_types; # hash parameter name -> parameter type
1.416     jms      7617: 
1.563     damieng  7618: # Reads parameter info from packages.tab into %standard_parms.
1.328     albertel 7619: sub load_parameter_names {
1.583     raeburn  7620:     open(my $config,"<","$Apache::lonnet::perlvar{'lonTabDir'}/packages.tab");
1.328     albertel 7621:     while (my $configline=<$config>) {
1.560     damieng  7622:         if ($configline !~ /\S/ || $configline=~/^\#/) { next; }
                   7623:         chomp($configline);
                   7624:         my ($short,$plain)=split(/:/,$configline);
                   7625:         my (undef,$name,$type)=split(/\&/,$short,3);
                   7626:         if ($type eq 'display') {
                   7627:             $standard_parms{$name} = $plain;
1.469     raeburn  7628:         } elsif ($type eq 'type') {
1.560     damieng  7629:                 $standard_parms_types{$name} = $plain;
1.469     raeburn  7630:         }
1.328     albertel 7631:     }
                   7632:     close($config);
                   7633:     $standard_parms{'int_pos'}      = 'Positive Integer';
                   7634:     $standard_parms{'int_zero_pos'} = 'Positive Integer or Zero';
1.575     raeburn  7635:     $standard_parms{'scoreformat'}  = 'Format for display of score';
1.328     albertel 7636: }
                   7637: 
1.563     damieng  7638: # Returns a parameter title for standard parameters, the name for others.
                   7639: #
                   7640: # @param {string} $name - parameter name
                   7641: # @returns {string}
1.292     www      7642: sub standard_parameter_names {
                   7643:     my ($name)=@_;
1.328     albertel 7644:     if (!%standard_parms) {
1.560     damieng  7645:         &load_parameter_names();
1.328     albertel 7646:     }
1.292     www      7647:     if ($standard_parms{$name}) {
1.560     damieng  7648:         return $standard_parms{$name};
1.446     bisitz   7649:     } else {
1.560     damieng  7650:         return $name;
1.292     www      7651:     }
                   7652: }
1.290     www      7653: 
1.563     damieng  7654: # Returns a parameter type for standard parameters, undef for others.
                   7655: #
                   7656: # @param {string} $name - parameter name
                   7657: # @returns {string}
1.469     raeburn  7658: sub standard_parameter_types {
                   7659:     my ($name)=@_;
                   7660:     if (!%standard_parms_types) {
                   7661:         &load_parameter_names();
                   7662:     }
                   7663:     if ($standard_parms_types{$name}) {
                   7664:         return $standard_parms_types{$name};
                   7665:     }
                   7666:     return;
                   7667: }
1.309     www      7668: 
1.563     damieng  7669: # Returns a parameter level title (not localized) from the parameter level name.
                   7670: #
                   7671: # @param {string} $name - parameter level name (recognized: resourcelevel|maplevel|maplevelrecurse|courselevel)
                   7672: # @returns {string}
1.557     raeburn  7673: sub standard_parameter_levels {
                   7674:     my ($name)=@_;
                   7675:     my %levels = (
                   7676:                     'resourcelevel'   => 'a single resource',
                   7677:                     'maplevel'        => 'the enclosing map/folder', 
                   7678:                     'maplevelrecurse' => 'the enclosing map/folder (recursive into sub-folders)',
                   7679:                     'courselevel'     => 'the general (course) level',
                   7680:                  );
                   7681:     if ($levels{$name}) {
                   7682:         return $levels{$name};
                   7683:     }
                   7684:     return;
                   7685: }
                   7686: 
1.560     damieng  7687: # Display log for parameter changes, blog postings, user notification changes.
1.563     damieng  7688: #
                   7689: # @param {Apache2::RequestRec} $r - the Apache request
1.285     albertel 7690: sub parm_change_log {
1.568     raeburn  7691:     my ($r,$parm_permission)=@_;
1.531     raeburn  7692:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   7693:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.569     raeburn  7694:     my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
1.414     droeschl 7695:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=settable',
1.473     amueller 7696:     text=>"Parameter Change Log"});
1.522     raeburn  7697:     my $js = '<script type="text/javascript">'."\n".
                   7698:              '// <![CDATA['."\n".
                   7699:              &Apache::loncommon::display_filter_js('parmslog')."\n".
                   7700:              '// ]]>'."\n".
                   7701:              '</script>'."\n";
                   7702:     $r->print(&Apache::loncommon::start_page('Parameter Change Log',$js));
1.327     albertel 7703:     $r->print(&Apache::lonhtmlcommon::breadcrumbs('Parameter Change Log'));
1.531     raeburn  7704:     &startSettingsScreen($r,'parmset',$crstype);
                   7705:     my %parmlog=&Apache::lonnet::dump('nohist_parameterlog',$cdom,$cnum);
1.311     albertel 7706: 
1.301     www      7707:     if ((keys(%parmlog))[0]=~/^error\:/) { undef(%parmlog); }
1.311     albertel 7708: 
1.522     raeburn  7709:     $r->print('<div class="LC_left_float">'.
                   7710:               '<fieldset><legend>'.&mt('Display of Changes').'</legend>'.
                   7711:               '<form action="/adm/parmset?action=parameterchangelog"
1.327     albertel 7712:                      method="post" name="parameterlog">');
1.446     bisitz   7713: 
1.311     albertel 7714:     my %saveable_parameters = ('show' => 'scalar',);
                   7715:     &Apache::loncommon::store_course_settings('parameter_log',
                   7716:                                               \%saveable_parameters);
                   7717:     &Apache::loncommon::restore_course_settings('parameter_log',
                   7718:                                                 \%saveable_parameters);
1.522     raeburn  7719:     $r->print(&Apache::loncommon::display_filter('parmslog').'&nbsp;'."\n".
                   7720:               '<input type="submit" value="'.&mt('Display').'" />'.
                   7721:               '</form></fieldset></div><br clear="all" />');
1.301     www      7722: 
1.568     raeburn  7723:     my $readonly = 1;
                   7724:     if ($parm_permission->{'edit'}) {
                   7725:         undef($readonly);
                   7726:     }
1.531     raeburn  7727:     my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
1.301     www      7728:     $r->print(&Apache::loncommon::start_data_table().&Apache::loncommon::start_data_table_header_row().
1.473     amueller 7729:           '<th>'.&mt('Time').'</th><th>'.&mt('User').'</th><th>'.&mt('Extent').'</th><th>'.&mt('Users').'</th><th>'.
1.568     raeburn  7730:           &mt('Parameter').'</th><th>'.&mt('Part').'</th><th>'.&mt('New Value').'</th>');
                   7731:     unless ($readonly) {
                   7732:         $r->print('<th>'.&mt('Announce').'</th>');
                   7733:     }
                   7734:     $r->print(&Apache::loncommon::end_data_table_header_row());
1.309     www      7735:     my $shown=0;
1.349     www      7736:     my $folder='';
                   7737:     if ($env{'form.displayfilter'} eq 'currentfolder') {
1.560     damieng  7738:         my $last='';
                   7739:         if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
                   7740:                 &GDBM_READER(),0640)) {
                   7741:             $last=$hash{'last_known'};
                   7742:             untie(%hash);
                   7743:         }
                   7744:         if ($last) { ($folder) = &Apache::lonnet::decode_symb($last); }
                   7745:     }
1.595     raeburn  7746:     my $numgroups = 0;
                   7747:     my @groups;
                   7748:     if ($env{'request.course.groups'} ne '') {
                   7749:         @groups = split(/:/,$env{'request.course.groups'});
                   7750:         $numgroups = scalar(@groups);
                   7751:     }
1.560     damieng  7752:     foreach my $id (sort {
                   7753:                 if ($parmlog{$b}{'exe_time'} ne $parmlog{$a}{'exe_time'}) {
                   7754:                     return $parmlog{$b}{'exe_time'} <=>$parmlog{$a}{'exe_time'}
                   7755:                 }
                   7756:                 my $aid = (split('00000',$a))[-1];
                   7757:                 my $bid = (split('00000',$b))[-1];
                   7758:                 return $bid<=>$aid;
1.473     amueller 7759:             } (keys(%parmlog))) {
1.294     www      7760:         my @changes=keys(%{$parmlog{$id}{'logentry'}});
1.560     damieng  7761:         my $count = 0;
                   7762:         my $time =
                   7763:             &Apache::lonlocal::locallocaltime($parmlog{$id}{'exe_time'});
                   7764:         my $plainname =
                   7765:             &Apache::loncommon::plainname($parmlog{$id}{'exe_uname'},
                   7766:                         $parmlog{$id}{'exe_udom'});
                   7767:         my $about_me_link =
                   7768:             &Apache::loncommon::aboutmewrapper($plainname,
                   7769:                             $parmlog{$id}{'exe_uname'},
                   7770:                             $parmlog{$id}{'exe_udom'});
                   7771:         my $send_msg_link='';
1.568     raeburn  7772:         if ((!$readonly) && 
                   7773:             (($parmlog{$id}{'exe_uname'} ne $env{'user.name'})
1.560     damieng  7774:             || ($parmlog{$id}{'exe_udom'} ne $env{'user.domain'}))) {
                   7775:             $send_msg_link ='<br />'.
                   7776:             &Apache::loncommon::messagewrapper(&mt('Send message'),
                   7777:                             $parmlog{$id}{'exe_uname'},
                   7778:                             $parmlog{$id}{'exe_udom'});
                   7779:         }
                   7780:         my $row_start=&Apache::loncommon::start_data_table_row();
                   7781:         my $makenewrow=0;
                   7782:         my %istype=();
                   7783:         my $output;
                   7784:         foreach my $changed (reverse(sort(@changes))) {
                   7785:                 my $value=$parmlog{$id}{'logentry'}{$changed};
                   7786:             my $typeflag = ($changed =~/\.type$/ &&
                   7787:                     !exists($parmlog{$id}{'logentry'}{$changed.'.type'}));
1.330     albertel 7788:             my ($realm,$section,$parmname,$part,$what,$middle,$uname,$udom,$issection,$realmdescription)=
1.581     raeburn  7789:                 &components($changed,$parmlog{$id}{'uname'},$parmlog{$id}{'udom'},$typeflag);
1.560     damieng  7790:             if ($env{'request.course.sec'} ne '') {
1.595     raeburn  7791:                 next if (($issection ne '') && (!(($issection eq $env{'request.course.sec'}) ||
                   7792:                                                   ($numgroups && (grep(/^\Q$issection\E$/,@groups))))));
1.560     damieng  7793:                 if ($uname ne '') {
                   7794:                     my $stusection = &Apache::lonnet::getsection($uname,$udom,$env{'request.course.id'});
                   7795:                     next if (($stusection ne '-1') && ($stusection ne $env{'request.course.sec'})); 
                   7796:                 }
                   7797:             }
                   7798:             if ($env{'form.displayfilter'} eq 'currentfolder') {
                   7799:                 if ($folder) {
                   7800:                     if ($middle!~/^\Q$folder\E/) { next; }
                   7801:                 }
                   7802:             }
                   7803:             if ($typeflag) {
                   7804:                 $istype{$parmname}=$value;
                   7805:                 if (!$env{'form.includetypes'}) { next; }
                   7806:             }
                   7807:             $count++;
                   7808:             if ($makenewrow) {
                   7809:                 $output .= $row_start;
                   7810:             } else {
                   7811:                 $makenewrow=1;
                   7812:             }
1.470     raeburn  7813:             my $parmitem = &standard_parameter_names($parmname);
1.560     damieng  7814:             $output .='<td>'.$realm.'</td><td>'.$section.'</td><td>'.
                   7815:                 &mt($parmitem).'</td><td>'.
                   7816:                 ($part?&mt('Part: [_1]',$part):&mt('All Parts')).'</td><td>';
                   7817:             my $stillactive=0;
                   7818:             if ($parmlog{$id}{'delflag'}) {
                   7819:                 $output .= &mt('Deleted');
                   7820:             } else {
                   7821:                 if ($typeflag) {
1.470     raeburn  7822:                     my $parmitem = &standard_parameter_names($value); 
                   7823:                     $parmitem = &mt($parmitem);
1.560     damieng  7824:                     $output .= &mt('Type: [_1]',$parmitem);
                   7825:                 } else {
1.584     raeburn  7826:                     my $toolsymb;
                   7827:                     if ($middle =~ /ext\.tool$/) {
                   7828:                         $toolsymb = $middle;
                   7829:                     }
1.560     damieng  7830:                     my ($level,@all)=&parmval_by_symb($what,$middle,
1.584     raeburn  7831:                         &Apache::lonnet::metadata($middle,$what,$toolsymb),
1.560     damieng  7832:                         $uname,$udom,$issection,$issection,$courseopt);
1.469     raeburn  7833:                     my $showvalue = $value;
                   7834:                     if ($istype{$parmname} eq '') {
                   7835:                         my $type = &standard_parameter_types($parmname);
                   7836:                         if ($type ne '') {
                   7837:                             if (&isdateparm($type)) {
                   7838:                                 $showvalue =
                   7839:                                     &Apache::lonlocal::locallocaltime($value);
                   7840:                             }
                   7841:                         }
                   7842:                     } else {
1.560     damieng  7843:                         if (&isdateparm($istype{$parmname})) {
                   7844:                             $showvalue = &Apache::lonlocal::locallocaltime($value);
1.622   ! raeburn  7845:                         } elsif (($istype{$parmname} eq 'string_grace') ||
        !          7846:                                  ($istype{$parmname} eq 'string_ip')) {
        !          7847:                             $showvalue =~ s/,/, /g;
1.560     damieng  7848:                         }
1.469     raeburn  7849:                     }
                   7850:                     $output .= $showvalue;
1.560     damieng  7851:                     if ($value ne $all[$level]) {
                   7852:                         $output .= '<br /><span class="LC_warning">'.&mt('Not active anymore').'</span>';
                   7853:                     } else {
                   7854:                         $stillactive=1;
                   7855:                     }
                   7856:                 }
1.473     amueller 7857:             }
1.568     raeburn  7858:             $output .= '</td>';
                   7859: 
                   7860:             unless ($readonly) { 
                   7861:                 $output .= '<td>';
                   7862:                 if ($stillactive) {
                   7863:                     my $parmitem = &standard_parameter_names($parmname);
                   7864:                     $parmitem = &mt($parmitem);
                   7865:                     my $title=&mt('Changed [_1]',$parmitem);
                   7866:                     my $description=&mt('Changed [_1] for [_2] to [_3]',
                   7867:                         $parmitem,$realmdescription,
                   7868:                         (&isdateparm($istype{$parmname})?&Apache::lonlocal::locallocaltime($value):$value));
                   7869:                     if (($uname) && ($udom)) {
                   7870:                         $output .=
                   7871:                         &Apache::loncommon::messagewrapper('Notify User',
                   7872:                                                            $uname,$udom,$title,
                   7873:                                                            $description);
                   7874:                     } else {
                   7875:                         $output .=
                   7876:                             &Apache::lonrss::course_blog_link($id,$title,
                   7877:                                                               $description);
                   7878:                     }
1.560     damieng  7879:                 }
1.568     raeburn  7880:                 $output .= '</td>';
1.560     damieng  7881:             }
1.568     raeburn  7882:             $output .= &Apache::loncommon::end_data_table_row();
1.473     amueller 7883:         }
1.560     damieng  7884:         if ($env{'form.displayfilter'} eq 'containing') {
                   7885:             my $wholeentry=$about_me_link.':'.
                   7886:             $parmlog{$id}{'exe_uname'}.':'.$parmlog{$id}{'exe_udom'}.':'.
                   7887:             $output;
                   7888:             if ($wholeentry!~/\Q$env{'form.containingphrase'}\E/i) { next; }
1.473     amueller 7889:         }
1.349     www      7890:         if ($count) {
1.560     damieng  7891:             $r->print($row_start.'<td rowspan="'.$count.'">'.$time.'</td>
                   7892:                         <td rowspan="'.$count.'">'.$about_me_link.
                   7893:             '<br /><tt>'.$parmlog{$id}{'exe_uname'}.
                   7894:                         ':'.$parmlog{$id}{'exe_udom'}.'</tt>'.
                   7895:             $send_msg_link.'</td>'.$output);
                   7896:             $shown++;
                   7897:         }
                   7898:         if (!($env{'form.show'} eq &mt('all')
                   7899:             || $shown<=$env{'form.show'})) { last; }
1.286     www      7900:     }
1.301     www      7901:     $r->print(&Apache::loncommon::end_data_table());
1.507     www      7902:     &endSettingsScreen($r);
1.284     www      7903:     $r->print(&Apache::loncommon::end_page());
                   7904: }
                   7905: 
1.560     damieng  7906: ##################################################
                   7907: # MISC !
                   7908: ##################################################
                   7909: 
1.563     damieng  7910: # Stores slot information.
1.560     damieng  7911: # Used by table UI
1.563     damieng  7912: # FIXME: I don't understand how this can work when the symb is not defined (if only a map was selected)
                   7913: #
                   7914: # @param {string} $slot_name - slot name
                   7915: # @param {string} $cdom - course domain
                   7916: # @param {string} $cnum - course number
                   7917: # @param {string} $symb - resource symb
                   7918: # @param {string} $uname - user name
                   7919: # @param {string} $udom - user domain
                   7920: # @returns {string} - 'ok' or error name
1.437     raeburn  7921: sub update_slots {
                   7922:     my ($slot_name,$cdom,$cnum,$symb,$uname,$udom) = @_;
                   7923:     my %slot=&Apache::lonnet::get_slot($slot_name);
                   7924:     if (!keys(%slot)) {
                   7925:         return 'error: slot does not exist';
                   7926:     }
                   7927:     my $max=$slot{'maxspace'};
                   7928:     if (!defined($max)) { $max=99999; }
                   7929: 
                   7930:     my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum,
                   7931:                                        "^$slot_name\0");
                   7932:     my ($tmp)=%consumed;
                   7933:     if ($tmp=~/^error: 2 / ) {
                   7934:         return 'error: unable to determine current slot status';
                   7935:     }
                   7936:     my $last=0;
                   7937:     foreach my $key (keys(%consumed)) {
                   7938:         my $num=(split('\0',$key))[1];
                   7939:         if ($num > $last) { $last=$num; }
                   7940:         if ($consumed{$key}->{'name'} eq $uname.':'.$udom) {
                   7941:             return 'ok';
                   7942:         }
                   7943:     }
                   7944: 
                   7945:     if (scalar(keys(%consumed)) >= $max) {
                   7946:         return 'error: no space left in slot';
                   7947:     }
                   7948:     my $wanted=$last+1;
                   7949: 
                   7950:     my %reservation=('name'      => $uname.':'.$udom,
                   7951:                      'timestamp' => time,
                   7952:                      'symb'      => $symb);
                   7953: 
                   7954:     my $success=&Apache::lonnet::newput('slot_reservations',
                   7955:                                         {"$slot_name\0$wanted" =>
                   7956:                                              \%reservation},
                   7957:                                         $cdom, $cnum);
1.438     raeburn  7958:     if ($success eq 'ok') {
                   7959:         my %storehash = (
                   7960:                           symb    => $symb,
                   7961:                           slot    => $slot_name,
                   7962:                           action  => 'reserve',
                   7963:                           context => 'parameter',
                   7964:                         );
1.526     raeburn  7965:         &Apache::lonnet::write_log('course','slotreservationslog',\%storehash,
1.524     raeburn  7966:                                    '',$uname,$udom,$cnum,$cdom);
1.438     raeburn  7967: 
1.526     raeburn  7968:         &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash,
1.524     raeburn  7969:                                    '',$uname,$udom,$uname,$udom);
1.438     raeburn  7970:     }
1.437     raeburn  7971:     return $success;
                   7972: }
                   7973: 
1.563     damieng  7974: # Deletes a slot reservation.
1.560     damieng  7975: # Used by table UI
1.563     damieng  7976: # FIXME: I don't understand how this can work when the symb is not defined (if only a map was selected)
                   7977: #
                   7978: # @param {string} $slot_name - slot name
                   7979: # @param {string} $cdom - course domain
                   7980: # @param {string} $cnum - course number
                   7981: # @param {string} $uname - user name
                   7982: # @param {string} $udom - user domain
                   7983: # @param {string} $symb - resource symb
                   7984: # @returns {string} - 'ok' or error name
1.437     raeburn  7985: sub delete_slots {
                   7986:     my ($slot_name,$cdom,$cnum,$uname,$udom,$symb) = @_;
                   7987:     my $delresult;
                   7988:     my %consumed = &Apache::lonnet::dump('slot_reservations',$cdom,
                   7989:                                          $cnum, "^$slot_name\0");
                   7990:     if (&Apache::lonnet::error(%consumed)) {
                   7991:         return 'error: unable to determine current slot status';
                   7992:     }
                   7993:     my ($tmp)=%consumed;
                   7994:     if ($tmp=~/^error: 2 /) {
                   7995:         return 'error: unable to determine current slot status';
                   7996:     }
                   7997:     foreach my $key (keys(%consumed)) {
                   7998:         if ($consumed{$key}->{'name'} eq $uname.':'.$udom) {
                   7999:             my $num=(split('\0',$key))[1];
                   8000:             my $entry = $slot_name.'\0'.$num;
                   8001:             $delresult = &Apache::lonnet::del('slot_reservations',[$entry],
                   8002:                                               $cdom,$cnum);
                   8003:             if ($delresult eq 'ok') {
                   8004:                 my %storehash = (
                   8005:                                   symb    => $symb,
                   8006:                                   slot    => $slot_name,
                   8007:                                   action  => 'release',
                   8008:                                   context => 'parameter',
                   8009:                                 );
1.526     raeburn  8010:                 &Apache::lonnet::write_log('course','slotreservationslog',\%storehash,
1.524     raeburn  8011:                                            1,$uname,$udom,$cnum,$cdom);
1.526     raeburn  8012:                 &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash,
1.524     raeburn  8013:                                            1,$uname,$udom,$uname,$udom);
1.437     raeburn  8014:             }
                   8015:         }
                   8016:     }
                   8017:     return $delresult;
                   8018: }
                   8019: 
1.563     damieng  8020: # Returns true if there is a current course.
1.560     damieng  8021: # Used by handler
1.563     damieng  8022: #
                   8023: # @returns {boolean}
1.355     albertel 8024: sub check_for_course_info {
                   8025:     my $navmap = Apache::lonnavmaps::navmap->new();
                   8026:     return 1 if ($navmap);
                   8027:     return 0;
                   8028: }
                   8029: 
1.563     damieng  8030: # Returns the current course host and host LON-CAPA version.
                   8031: #
                   8032: # @returns {Array} - (course hostname, major version number, minor version number)
1.514     raeburn  8033: sub parameter_release_vars { 
1.504     raeburn  8034:    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                   8035:    my $chome = $env{'course.'.$env{'request.course.id'}.'.home'};
                   8036:    my $chostname = &Apache::lonnet::hostname($chome);
                   8037:    my ($cmajor,$cminor) = 
                   8038:        split(/\./,&Apache::lonnet::get_server_loncaparev($cdom,$chome));
                   8039:    return ($chostname,$cmajor,$cminor);
                   8040: }
                   8041: 
1.563     damieng  8042: # Checks if the course host version can handle a parameter required version,
                   8043: # and if it does, stores the release needed for the course.
                   8044: #
                   8045: # @param {string} $name - parameter name
                   8046: # @param {string} $value - parameter value
                   8047: # @param {string} $valmatch - name of the test used for checking the value
                   8048: # @param {string} $namematch - name of the test used for checking the name
                   8049: # @param {string} $needsrelease - version needed by the parameter, major.minor
                   8050: # @param {integer} $cmajor - course major version number
                   8051: # @param {integer} $cminor - course minor version number
                   8052: # @returns {boolean} - true if a newer version is needed
1.514     raeburn  8053: sub parameter_releasecheck {
1.557     raeburn  8054:     my ($name,$value,$valmatch,$namematch,$needsrelease,$cmajor,$cminor) = @_;
1.504     raeburn  8055:     my $needsnewer;
                   8056:     my ($needsmajor,$needsminor) = split(/\./,$needsrelease);
                   8057:     if (($cmajor < $needsmajor) || 
                   8058:         ($cmajor == $needsmajor && $cminor < $needsminor)) {
                   8059:         $needsnewer = 1;
1.557     raeburn  8060:     } elsif ($name) {
                   8061:         if ($valmatch) {
                   8062:             &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.'::'.$valmatch.':'});
                   8063:         } elsif ($value) { 
                   8064:             &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.':'.$value.'::'});
                   8065:         }
                   8066:     } elsif ($namematch) {
                   8067:         &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter::::'.$namematch});
1.504     raeburn  8068:     }
                   8069:     return $needsnewer;
                   8070: }
                   8071: 
1.568     raeburn  8072: sub get_permission {
                   8073:     my %permission;
                   8074:     my $allowed = 0;
                   8075:     return (\%permission,$allowed) unless ($env{'request.course.id'});
                   8076:     if ((&Apache::lonnet::allowed('opa',$env{'request.course.id'})) ||
                   8077:         (&Apache::lonnet::allowed('opa',$env{'request.course.id'}.'/'.
                   8078:                   $env{'request.course.sec'}))) {
                   8079:         %permission= (
                   8080:                        'edit'               => 1,
                   8081:                        'set'                => 1,
                   8082:                        'setoverview'        => 1,
                   8083:                        'addmetadata'        => 1,
                   8084:                        'ordermetadata'      => 1,
                   8085:                        'setrestrictmeta'    => 1,
                   8086:                        'newoverview'        => 1,
                   8087:                        'setdefaults'        => 1,
                   8088:                        'settable'           => 1,
                   8089:                        'parameterchangelog' => 1,
                   8090:                        'cleanparameters'    => 1,
                   8091:                        'dateshift1'         => 1,
                   8092:                        'dateshift2'         => 1,
                   8093:                        'helper'             => 1,
                   8094:          );
                   8095:     } elsif ((&Apache::lonnet::allowed('vpa',$env{'request.course.id'})) ||
                   8096:              (&Apache::lonnet::allowed('vpa',$env{'request.course.id'}.'/'.
                   8097:                   $env{'request.course.sec'}))) {
                   8098:         %permission = (
                   8099:                        'set'                => 1,
                   8100:                        'settable'           => 1,
                   8101:                        'newoverview'        => 1,
                   8102:                        'setoverview'        => 1,
                   8103:                        'parameterchangelog' => 1,
                   8104:                       );
                   8105:     }
                   8106:     foreach my $perm (values(%permission)) {
                   8107:         if ($perm) { $allowed=1; last; }
                   8108:     }
                   8109:     return (\%permission,$allowed);
                   8110: }
                   8111: 
1.560     damieng  8112: ##################################################
                   8113: # HANDLER
                   8114: ##################################################
                   8115: 
                   8116: # Main handler for lonparmset.
                   8117: # Sub called based on request parameters action and command:
                   8118: # no command or action: print_main_menu
                   8119: # command 'set': assessparms (direct access to table mode for a resource)
                   8120: #                (this can also be accessed simply with the symb parameter)
                   8121: # action 'setoverview': overview (display all existing parameter settings)
                   8122: # action 'addmetadata': addmetafield (called to add a portfolio metadata field)
                   8123: # action 'ordermetadata': order_meta_fields (called to order portfolio metadata fields)
                   8124: # action 'setrestrictmeta': setrestrictmeta (display or save portfolio metadata)
                   8125: # action 'newoverview': newoverview (overview mode)
                   8126: # action 'setdefaults': defaultsetter (UI to change parameter setting default actions)
                   8127: # action 'settable': assessparms (table mode)
                   8128: # action 'parameterchangelog': parm_change_log (display log for parameter changes,
                   8129: #                              blog postings, user notification changes)
                   8130: # action 'cleanparameters': clean_parameters (unused)
                   8131: # action 'dateshift1': date_shift_one (overview mode, shift all dates)
                   8132: # action 'dateshift2': date_shift_two (overview mode, shift all dates)
1.30      www      8133: sub handler {
1.43      albertel 8134:     my $r=shift;
1.30      www      8135: 
1.376     albertel 8136:     &reset_caches();
                   8137: 
1.414     droeschl 8138:     &Apache::loncommon::content_type($r,'text/html');
                   8139:     $r->send_http_header;
                   8140:     return OK if $r->header_only;
                   8141: 
1.193     albertel 8142:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.473     amueller 8143:                         ['action','state',
1.205     www      8144:                                              'pres_marker',
                   8145:                                              'pres_value',
1.206     www      8146:                                              'pres_type',
1.506     www      8147:                                              'filter','part',
1.390     www      8148:                                              'udom','uname','symb','serial','timebase']);
1.131     www      8149: 
1.83      bowersj2 8150: 
1.193     albertel 8151:     &Apache::lonhtmlcommon::clear_breadcrumbs();
1.194     albertel 8152:     &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/parmset",
1.507     www      8153:                         text=>"Content and Problem Settings",
1.473     amueller 8154:                         faq=>10,
                   8155:                         bug=>'Instructor Interface',
1.442     droeschl 8156:                                             help =>
                   8157:                                             'Parameter_Manager,Course_Environment,Parameter_Helper,Parameter_Overview,Table_Mode'});
1.203     www      8158: 
1.30      www      8159: # ----------------------------------------------------- Needs to be in a course
1.568     raeburn  8160:     my ($parm_permission,$allowed) = &get_permission();
1.355     albertel 8161:     my $exists = &check_for_course_info();
                   8162: 
1.568     raeburn  8163:     if ($env{'request.course.id'} && $allowed && $exists) {
1.193     albertel 8164:         #
                   8165:         # Main switch on form.action and form.state, as appropriate
                   8166:         #
                   8167:         # Check first if coming from someone else headed directly for
                   8168:         #  the table mode
1.568     raeburn  8169:         if (($parm_permission->{'set'}) && 
                   8170:             ((($env{'form.command'} eq 'set') && ($env{'form.url'})
                   8171:                 && (!$env{'form.dis'})) || ($env{'form.symb'}))) {
                   8172:             &assessparms($r,$parm_permission);
1.193     albertel 8173:         } elsif (! exists($env{'form.action'})) {
                   8174:             &print_main_menu($r,$parm_permission);
1.568     raeburn  8175:         } elsif (!$parm_permission->{$env{'form.action'}}) {
                   8176:             &print_main_menu($r,$parm_permission);
1.414     droeschl 8177:         } elsif ($env{'form.action'} eq 'setoverview') {
1.568     raeburn  8178:             &overview($r,$parm_permission);
1.560     damieng  8179:         } elsif ($env{'form.action'} eq 'addmetadata') {
                   8180:             &addmetafield($r);
                   8181:         } elsif ($env{'form.action'} eq 'ordermetadata') {
                   8182:             &order_meta_fields($r);
1.414     droeschl 8183:         } elsif ($env{'form.action'} eq 'setrestrictmeta') {
1.560     damieng  8184:             &setrestrictmeta($r);
1.414     droeschl 8185:         } elsif ($env{'form.action'} eq 'newoverview') {
1.568     raeburn  8186:             &newoverview($r,$parm_permission);
1.414     droeschl 8187:         } elsif ($env{'form.action'} eq 'setdefaults') {
1.560     damieng  8188:             &defaultsetter($r);
                   8189:         } elsif ($env{'form.action'} eq 'settable') {
1.568     raeburn  8190:             &assessparms($r,$parm_permission);
1.414     droeschl 8191:         } elsif ($env{'form.action'} eq 'parameterchangelog') {
1.568     raeburn  8192:             &parm_change_log($r,$parm_permission);
1.414     droeschl 8193:         } elsif ($env{'form.action'} eq 'cleanparameters') {
1.560     damieng  8194:             &clean_parameters($r);
1.414     droeschl 8195:         } elsif ($env{'form.action'} eq 'dateshift1') {
1.390     www      8196:             &date_shift_one($r);
1.414     droeschl 8197:         } elsif ($env{'form.action'} eq 'dateshift2') {
1.390     www      8198:             &date_shift_two($r);
1.446     bisitz   8199:         }
1.43      albertel 8200:     } else {
1.1       www      8201: # ----------------------------- Not in a course, or not allowed to modify parms
1.560     damieng  8202:         if ($exists) {
                   8203:             $env{'user.error.msg'}=
                   8204:             "/adm/parmset:opa:0:0:Cannot modify assessment parameters";
                   8205:         } else {
                   8206:             $env{'user.error.msg'}=
                   8207:             "/adm/parmset::0:1:Course environment gone, reinitialize the course";
                   8208:         }
                   8209:         return HTTP_NOT_ACCEPTABLE;
1.43      albertel 8210:     }
1.376     albertel 8211:     &reset_caches();
                   8212: 
1.43      albertel 8213:     return OK;
1.1       www      8214: }
                   8215: 
                   8216: 1;
                   8217: __END__
                   8218: 
                   8219: 

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