Diff for /loncom/interface/lonblockingmenu.pm between versions 1.2 and 1.29

version 1.2, 2011/12/28 22:09:44 version 1.29, 2021/01/02 21:07:36
Line 1 Line 1
 # The LearningOnline Network with CAPA  # The LearningOnline Network with CAPA
 # Routines for configuring blocking to collaborative functions, and specific  # Routines for configuring blocking of access to collaborative functions, 
 # resources during an exam   # and specific resources during an exam
 #  #
 # $Id$  # $Id$
 #  #
Line 26 Line 26
 #  #
 # http://www.lon-capa.org/  # http://www.lon-capa.org/
 #  #
 ###############################################################  ##############################################################
 ##############################################################  ##############################################################
   
 =pod  =pod
Line 44  lonblockingmenu provides an interface fo Line 44  lonblockingmenu provides an interface fo
 This module is used to configure blocking of access to collaborative tools  This module is used to configure blocking of access to collaborative tools
 and/or resources during an exam.  and/or resources during an exam.
   
   =head1 OVERVIEW
   
   To support high-stakes testing, LON-CAPA provides Coordinators with the
   ability to disable communication and collaborative features within the
   system for the duration of an exam.
   
   Features which can be disabled include:
   (a) those which a student could use to communicate with another student.
   Messaging, discussion, chat, blogs, and some functionality in groups fall 
   into this category.
   (b) those which a student could use to access materials prepared by the
   student in advance of an exam, (e.g., for use during an online exam, to
   gain an unfair advantage). Blogs and portfolio fall into this category.
   (c) those which a student could use to display or save content within
   the course itself (outside the exam folder). Printouts and resources
   fall into this category.
   
   For communication blocking to be truly effective in preventing unwanted
   communication, or access to online materials, online testing needs to
   take place in a lab setting where use of tools outside LON-CAPA, and use
   of web sites beyond LON-CAPA are unavailable.
   
   Access to specified folder(s) and/or resources in the course contents 
   can be restricted for the duration of an exam.
   
   Exam blocks are of two types:
   (a) Blocks with a defined start and end date.
   (b) Blocks associated with a timed interval set for a specific folder,
   or resource.
   
   When a student attempts to use a collaboration or communication feature
   which is currently blocked, information will be available about the
   duration of the block, and the identity of the Course Coordinator who
   set the block.
   
   Although LON-CAPA communication can be blocked during an exam, course
   personnel with the 'evb' (evade blocking) privilege will continue to
   receive LON-CAPA messages sent from students in a course with an active
   block on messaging. Students will not be able to view messages sent by
   other students in the same course for the duration of the blocking event.
   
   Because students may be enrolled in more than one LON-CAPA course at a time
   it is important to use reasonable time windows for blocking events, or, in
   the case of blocks triggered by clicking a button to start a timed quiz, 
   quiz durations that are of limited duration. This is especially important
   when blocking prtfolio access, as other courses may require students to use
   the portfolio as a mechanism for submitting assignments.
   
   Information about blocks in a course will be cached for 10 minutes, so,
   as with parameters set for resources, it can take up to 10 minutes for
   new blocks, or changes to existing blocks, to propagate to other servers.
   
   Changes to existing blocks on the server hosting your current session
   are available immediately, as cached data on blocks is devalidated
   automatically on the current server whenever a change is made to a 
   block (including deletion), or when a new block is added. 
   
 =head1 INTERNAL SUBROUTINES  =head1 INTERNAL SUBROUTINES
   
 =over  =over
   
   =item &get_permission()
   
   Returns information about permission user has to set/modify exam
   blocking events.
   
   Inputs: None
   
   Outputs: 2
       $readonly - true if modification of blocking events is prohibited.
   
       $allowed  - true if blocking events information can be shown.
   
   
   =item &get_timed_items()
   
   Provides perl data structure with information about timed interval
   parameters set in a course.
   
   Inputs: 2 (optional)
          $cdom - course's domain
   
          $cnum - course's ID
   
   Output: 1 Hash 
          nested hashes containing information about timed interval
          parameters in course). Top level keys are type: course,
          map, resource. Next inner keys are map or symb. Next
          inner keys are scope (all, section, group, users).
          Values are interval (in seconds).
   
 =item &blockstore()  =item &blockstore()
   
   Stores changes to exam blocks in comm_block.db file for course.
   Processes deletions, modifications and additions.
   
   Inputs: 4
         $r = request object
   
         $crstype - Container type: Course or Community.
   
         $blockcount - Total number of blocking events in course.
   
         $currblockrecs - Ref to hash of current blocks in course.
   
   Outputs: 2
         $changestotal - Total number of changes made.
   
         $output - Information about changes made.
   
   
 =item &get_dates_from_form()  =item &get_dates_from_form()
   
   Extract start and end dates from web form input for blocks with
   defined start/end time.
   
   Inputs: 1 - $item - numeric ID of current block.
   
   Outputs: 2 - $startdate, $enddate (UNIX times for start and end times
                for blocks with defined start/end   
   
   
 =item &get_blockdates()  =item &get_blockdates()
   
   Retrieves contents of comm_block.db file for a course.
   
   Inputs: 1 - $records - reference to hash to contain blocks 
   
   Outputs: 1 - $blockcount - number of blocks
   
   Side Effects: populates records hashref.
   
   
 =item &get_block_choices()  =item &get_block_choices()
   
   Extract information from web form about which communication/
   collaboration features are to be blocked, for a particular event,
   and also which content areas will have access blocked for the
   duration of the block.
   
   Inputs: 3 
       - $item - numeric ID of current block 
   
       - $map_ref - reference to hash mapping numeric IDs to map urls 
   
       - $symb_ref - reference to hash mapping numeric IDs to symbs
   
   Outputs: 2
       - $blocktypes - reference to hash of features to be blocked
   
       - $blockdocs - boolean - 0 if no blocking of content, 1 if blocking 
                                of content access 
   
   
   =item &check_release_required()
   
   Update LON-CAPA version requirements for course if blocked items
   (content) or blocking type (triggered by student starting timer)
   require specific LON-CAPA version (i.e., 2.11).
   
   Inputs: 3 - $value - type of constraint (currently: 'docs', 'printout' or 'timer'),
               $chomemajor - course's home server LON-CAPA major version number.
               $chomeminor - course's home server LON-CAPA minor version number.
   
   Outputs: 2 - status ('ok' or 'fail') and LON-CAPA version needed.
   
   =over
   
                A status of 'fail' will be returned if the 
                LON-CAPA version installed on the course's 
                home server is older than the version 
                requirement for the blocking type.
                For a trigger type event, the requested
                blocking event will not be added if 
                the course's home server version is old to
                support that type of block.
   
   =back
   
   Side Effects: &update_released_required() called in lonnet, if
                 course's home server version is requied version or 
                 newer; will update version requirements for course to
                 a more recent version requirement than currently in
                 effect.
   
   
 =item &display_blocker_status()  =item &display_blocker_status()
   
   Generates web form elements used to display, cancel, or modify 
   existing blocking events. 
   
   Inputs: 8 
         - $r - Apache request object
   
         - $records - Reference to hash of current blocks
   
         - $ltext - Reference to hash of phrases (localized)
   
         - $intervals - Reference to hash of parameters for timed intervals
   
         - $navmap - navmaps object.
   
         - $errormsg - error message for display, if navmaps object
                       could not be instantiated
   
         - $blockcount - number of existing blocking events in course
   
         - $readonly - if true, modification not allowed.
   
   
   Output: None
   
   Side Effects: prints web form elements (in a table) for current blocks. 
   
   =item &convlim()
   
   Convert a time interval used for a timed quiz (in seconds) to
   days, hours. minutes and seconds.
   
   Inputs: 1 - $timelimit  - time interval in seconds
   
   Outputs: 1 - $output - time in format: DD days, HH hours, MM minutes, SS seconds  
   
   
 =item &display_addblocker_table()  =item &display_addblocker_table()
   
   Generate web form elements used to define a new blocking event. 
   
   Inputs: 6
       - $r - Apache resource object
   
       - $parmcount - current ID for block (same as number of current blocks,
                      block IDs in web form have zero-based index)
   
       - $ltext - reference to hash of phrases (localized)
   
       - $intervals - Reference to hash of parameters for timed intervals
   
       - $navmap - navmaps object
   
       - $errormsg - error message for display, if navmaps object
                     could not be instantiated
   
   Outputs: None
    
   Side Effects: prints web form elements (in a table) for adding a new block.
   
   
   =item &blocker_checkboxes()
   
   Generates web form elements in a table for checkboxes used to indicate
   which types of communication/collaboration and/or content should be blocked.
   
   Inputs: 4 
       - $parmcount - numeric ID of current block
   
       - $blocks - reference to hash of functionalities to block 
   
       - $jschg - text of javascript call to execute when checkbox clicked  
                  use within a box via 'onclick="$jchg"'
    
       - $lookups - reference to hash to map urls or symbs to numeric IDs
                    used to populate hodden form elements containing list
                    of resources and folders with access blocking currently set.
   
   Output: 1 - HTML for table of checkboxes for current block  
   
   
   =item &create_interval_form()
   
   Creates web form elements used to select one of the defined timed interval 
   items in the course for use in an exam block of type: "Triggered by 
   Activating Timer".
   
   Inputs: 8 (four required, last four optional)
      - $intervals - Reference to hash of parameters for timed intervals
   
      - $parmcount - numeric ID of current block
   
      - $navmap - navmaps object
   
      - $context - this will be "accesstimes" if called by lonaccesstimes.pm,
                   or "blocking" if called internally by lonblockingmenu.pm
   
      - $currkey - current interval (where this is a block already using
                   an interval-based trigger).  
   
      - $jschg - text of javascript call to execute when radiobutton clicked
                 use within a box via 'onclick="$jchg"'
   
      - $itemname - name/scope of current interval used for this block 
   
      - $iteminfo - Expandable/collapsible block showing which users are
                    able to activate the timer using the current trigger item.
   
   Outputs: 1 - $intervalform - web form elements used to select a time interval
   
   
   =item &interval_details()
   
   Creates name/scope of current interval and expandable/collapsible
   showing which interval parameters apply to the current folder/resource
   
   Inputs: 6
   
       - $item - course, map url, or resource symb
   
       - $type - course, map, or resource
   
       - $url  - url of item (null if item is course).
   
       - $navmap - navmaps object
   
       - $intervals - Reference to hash of parameters for timed intervals
   
       - $parmcount - unique ID for current element.
   
   
   Outputs: 2
   
      - $itemname - name/scope of interval (timer) parameter
   
      - $iteminfo - Expandable/collapsible block showing which interval
                    (timer) parameters affect the current folder or resource.
   
   
   =item &trigger_details_toggle()
    
   Creates link used to expand item showing information about timer for current
   trigger for exam block. 
   
   Inputs: 1 - $parmcount - numericID of exam block in web form. 
   
   Outputs: 1 - returns HTML for link to display contents of information item 
   
   
   =item &show_timer_path()
   
   Display hierarchy of names of folders/sub-folders containing the current
   item identified as an item with an interval timer set.
   
   Inputs: 3
       - $type - map or resource
   
       - $item - map URL or resource symb
   
       - $navmap - navmaps object
   
   Outputs: 1 - HTML containing hierarchy of folders/subfolders (raquo entity separated).  
   
   
 =item &blocktype_text()  =item &blocktype_text()
   
 =back    Inputs: None
   
   Output: 2 
        - $typeorder - reference to array of blockable communication/collaboration/content
   
        - $types -reference to hash of descriptions (localized) of blockable types.
    
   
   =item &blockingmenu_javascript()
   
   Create Javascript used to launch pop-up used for content selection, and to
   toggle visibility of a number of expandable/collapsible divs.
   
   Inputs: 1 - $blockcount - Total number of blocks in course's comm_block.db
                             database file. 
   
   Output: 1 - Javascript (with <script></script> tags) for functions used to:
               (a) launch pop-up window for selection of course content to which
               access could be blocked. 
               (b) toggle visibility of a number of divs:
   
   =over 
   
   =item *  for block type - defined dates or timer activated
   
   =item *  for action to take -- add or modify block
   
   =back
   
   
   =item &details_javascript()
   
   Create Javascript to toggle visibility of unordered list item
   containing details about item with timed interval parameter.
   
   Inputs: none
   
   Output: 1 Javascript (with <script></script> tags) for functions used to:
             toggle visibility of unordered list for display of detailed
             information about intervals.
   
   =back
   
 =cut  =cut
   
Line 73  use Apache::lonnet; Line 449  use Apache::lonnet;
 use Apache::Constants qw(:common :http);  use Apache::Constants qw(:common :http);
 use Apache::loncommon();  use Apache::loncommon();
 use Apache::lonhtmlcommon();  use Apache::lonhtmlcommon();
   use Apache::lonparmset();
   use Apache::loncourserespicker();
 use HTML::Entities();  use HTML::Entities();
 use Apache::lonlocal;  use Apache::lonlocal;
 use lib '/home/httpd/lib/perl/';  use lib '/home/httpd/lib/perl/';
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
   
   my $registered_cleanup;
   my $modified_courses;
   
 sub handler {  sub handler {
     my $r=shift;      my $r=shift;
   
Line 98  sub handler { Line 479  sub handler {
   
 # ----------------------------------------------------------- Permissions check  # ----------------------------------------------------------- Permissions check
   
     unless ((!&Apache::lonnet::allowed('dcm',$env{'request.course.id'})) ||      my ($readonly,$allowed) = &get_permission();
             (!&Apache::lonnet::allowed('dcm',$env{'request.course.id'}.      unless ($allowed) {
                                       '/'.$env{'request.course.sec'}))) {          $env{'user.error.msg'}=
        "/adm/setblock:dcm:0:0:Cannot view/set blocking of communications in a course";
         return HTTP_NOT_ACCEPTABLE;          return HTTP_NOT_ACCEPTABLE;
     }      }
   
 # -----------------------------Get action and calling context from query string  # -----------------------------Get action and calling context from query string
   
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['action','caller']);      $registered_cleanup=0;
       @{$modified_courses}=();
   
       &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                                               ['action','caller','block']);
   
       my $crstype = &Apache::loncommon::course_type();
       my $action = $env{'form.action'};
       my %records = ();
       my $blockcount = 0;
   
   # ------------------------------------------------------ Retrieve current blocks
       $blockcount = &get_blockdates(\%records);
   
   # -------------------- Generate display for pop-up of Maps and Resources blocked   
       if ($action eq 'showdocs') {
           my ($navmap,$errormsg) = 
               &Apache::loncourserespicker::get_navmap_object($crstype,'examblock');
           if (ref($navmap)) {
               my (%blockedmaps,%blockedresources);
               if ($env{'form.block'} =~ /^\d+$/) {
                   my @currblocks = sort(keys(%records));
                   my $block = $currblocks[$env{'form.block'}];
                   if (($block ne '') && (ref($records{$block}) eq 'HASH')) {
                       if (ref($records{$block}{'blocks'}) eq 'HASH') {
                           if (ref($records{$block}{'blocks'}{'docs'}) eq 'HASH') {
                               if (ref($records{$block}{'blocks'}{'docs'}{'maps'}) eq 'HASH') {
                                   %blockedmaps = %{$records{$block}{'blocks'}{'docs'}{'maps'}};
                               }
                               if (ref($records{$block}{'blocks'}{'docs'}{'resources'}) eq 'HASH') {
                                   %blockedresources = %{$records{$block}{'blocks'}{'docs'}{'resources'}};
                               }
                           }
                       }
                   }
               }
               $r->print(&Apache::loncourserespicker::create_picker($navmap,
                                        'examblock','resourceblocks',$crstype,
                                        \%blockedmaps,\%blockedresources,
                                        $env{'form.block'},'','',undef,undef,$readonly));
           } else {
               $r->print($errormsg);
           }
           return OK;
       }
   
 # ----------------------------------------------------------------- Breadcrumbs  # -------------------------- Store changes and retrieve latest block information
       my $storeresult;
       unless ($readonly) {
           if ($env{'form.action'} eq 'store') {
               (my $numchanges,$storeresult) = &blockstore($r,$crstype,$blockcount,\%records);
               if ($numchanges > 0) {
                   $blockcount = &get_blockdates(\%records);
               }
           }
       }
   
   # ------------------------------------------------------------------ Breadcrumbs
     &Apache::lonhtmlcommon::clear_breadcrumbs();      &Apache::lonhtmlcommon::clear_breadcrumbs();
     if ($env{'form.caller'} eq 'email') {        if ($env{'form.caller'} eq 'email') {  
         &Apache::lonhtmlcommon::add_breadcrumb          &Apache::lonhtmlcommon::add_breadcrumb
Line 123  sub handler { Line 559  sub handler {
     }      }
     &Apache::lonhtmlcommon::add_breadcrumb      &Apache::lonhtmlcommon::add_breadcrumb
         ({href=>'/adm/setblock',          ({href=>'/adm/setblock',
           text=>'Blocking communication/resource access'});            text=>'Blocking communication/content access'});
   
     $r->print(&Apache::loncommon::start_page('Blocking communication/resource access').      my $js = &blockingmenu_javascript($blockcount).
               &Apache::lonhtmlcommon::breadcrumbs('Blocking communication/resource access'));               &details_javascript();
   
 # ----------------------------------------------------------- Permissions check      $r->print(
           &Apache::loncommon::start_page('Blocking communication/content access',$js).
           &Apache::lonhtmlcommon::breadcrumbs('Blocking communication/content access'));
   
     my $usertype;      my $usertype;
     my $crstype = &Apache::loncommon::course_type();  
     if ($crstype eq 'Community') {      if ($crstype eq 'Community') {
         $usertype = 'members';          $usertype = 'members';
     } else {      } else {
         $usertype = 'students';          $usertype = 'students';
     }      }
     my $lctype = lc($crstype);      my $lctype = lc($crstype);
     my %lt=&Apache::lonlocal::texthash(      my %lt=&Apache::lonlocal::texthash (
             'cbds' => 'Communication blocking during scheduled exams',              'cbds' => 'Blocking communication and/or content access during exams',
             'desc' => "You can use communication blocking to prevent $usertype enrolled in this $lctype from displaying LON-CAPA messages sent by other $usertype during an online exam. As blocking of communication could potentially interrupt legitimate communication between $usertype who are also both enrolled in a different LON-CAPA course or community, please be careful that you select the correct start and end times for your scheduled exam when setting or modifying these parameters.",              'prev' => "For the duration of an exam, or a timed quiz, students in this course can be prevented from:",
              'mecb' => 'Modify existing communication blocking periods',              'flow' => "For the duration of an exam, or a timed quiz, event-driven interruptions to a student's workflow can be suppressed:",
              'ncbc' => 'No communication blocks currently saved',              'blca' => "Blocks can potentially interrupt legitimate communication between $usertype who are also both enrolled in a different LON-CAPA $lctype.",
              'stor' => 'Save',              'pobl' => "Portfolio blocking can impact a student's ability to complete assignments in courses besides your own. Please use this feature wisely.",
               'actt' => "Action to take:",
               'addn' => 'Add new blocking event',
               'mexb' => 'Modify existing blocking event(s)', 
               'ncbc' => 'There are no blocking events currently saved.',
               'stor' => 'Save',
     );      );
   
     my %ltext = &Apache::lonlocal::texthash(      my %ltext = &Apache::lonlocal::texthash(
             'dura' => 'Duration',              'type' => 'Type',
               'defs' => 'Defined Start/End',
               'trig' => 'Triggered by Activating Timer', 
             'setb' => 'Set by',              'setb' => 'Set by',
             'even' => 'Event',              'even' => 'Event',
             'blck' => 'Blocked?',              'blck' => 'Blocked?',
             'actn' => 'Action',  
             'star' => 'Start',              'star' => 'Start',
             'endd' => 'End'              'endd' => 'End',
               'chda' => 'Choose dates',
               'chtr' => 'Choose trigger',
               'when' => 'When using defined start/end times for an event, please set dates carefully.',
               'yes'  => 'Yes',
               'no'   => 'No',
     );      );
   
     $r->print('<h3>'.$lt{'cbds'}.'</h3>');      $r->print('<h3>'.$lt{'cbds'}.'</h3>');
   
   # ---------------------------------------------------- Get Time Limit parameters
       my %intervals = &get_timed_items();
   
   # -------------------------------------------- Display information about changes 
     if ($env{'form.action'} eq 'store') {      if ($env{'form.action'} eq 'store') {
         &blockstore($r);          $r->print($storeresult);
       } else {
           $r->print(
               $lt{'prev'}.
               '<ul>'."\n".
               '<li>'.&mt("displaying LON-CAPA messages sent by other $usertype in the $lctype").'</li>'."\n".
               '<li>'.&mt("displaying or posting to LON-CAPA discussion boards or live chat in the $lctype").'</li>'."\n".
               '<li>'.&mt('accessing content in LON-CAPA portfolios, blogs, or user information pages').'</li>'."\n".
               '<li>'.&mt("generating printouts of $lctype content").'</li>'.
               '<li>'.&mt("displaying the LON-CAPA gradebook in the $lctype").'</li>'.
               '<li>'.&mt("searching $lctype content by keyword").'</li>'.  
               '<li>'.&mt("accessing $lctype content in specified folders or resources").'</li>'.
               '<li>'.&mt("changing user's own password").'</li>'.
               '</ul>'.
               $lt{'flow'}.
               '<ul>'."\n".
               '<li>'.&mt("re-initialization of cached course structure, when a change has been made to $lctype content by a Coordinator").'</li>'.
               '<li>'.&mt('display of Critical Messages when navigation arrows used to move to the adjacent resource').'</li>'.
               '</ul>'.
               '<p class="LC_warning">'.$lt{'blca'}.'<br />'.$lt{'pobl'}.'</p>'
           );
     }      }
   
     $r->print($lt{'desc'}.'<br /><br />  # ------------------------ Choose between modifying existing block or adding new
                <form name="blockform" method="post" action="/adm/setblock?action=store">      $r->print('<form name="blockform" method="post" action="/adm/setblock?action=store">');
              ');  
   
     $r->print('<h4>'.$lt{'mecb'}.'</h4>');      unless ($readonly) {
     my %records = ();          if ($blockcount > 0) {
     my $blockcount = 0;              $r->print(<<"END");
     my $parmcount = 0;  <div class="LC_left_float">
     &get_blockdates(\%records,\$blockcount);  <fieldset><legend>$lt{'actt'}</legend>
     if ($blockcount > 0) {  <span class="LC_nobreak">
         $parmcount = &display_blocker_status($r,\%records,\%ltext);  <label><input type="radio" name="blockaction" value="modify" id="modifyaction" 
   onclick="toggleAddModify();" checked="checked" />$lt{'mexb'}</label>
   </span>
   <br />
   <span class="LC_nobreak">
   <label><input type="radio" name="blockaction" value="add" id="addaction" 
   onclick="toggleAddModify();" />$lt{'addn'}</label>
   </span>
   </fieldset>
   </div>
   <br clear="all" />
   <div id="showadd" style="display:none">
   END
           } else {
               $r->print($lt{'ncbc'}.'<br /><br />'.
                         '<h4>'.$lt{'addn'}.'</h4>'.
                         '<input type="hidden" name="blockaction" value="add" />');
           }
       }
       my ($navmap,$errormsg) =
           &Apache::loncourserespicker::get_navmap_object($crstype,'examblock');
   
   # --------------------------------------------- Interface for adding a new block
       unless ($readonly) {
           &display_addblocker_table($r,$blockcount,\%ltext,\%intervals,
                                     $navmap,$errormsg);
           if ($blockcount > 0) {
               $r->print('</div>');
           }
       }
   # ------------------------------------------------ Interface for existing blocks
       if (!$blockcount) {
           if ($readonly) {
               $r->print($lt{'ncbc'}.'<br />');
           }
     } else {      } else {
         $r->print($lt{'ncbc'}.'<br /><br />');          &display_blocker_status($r,\%records,\%ltext,\%intervals,
                                   $navmap,$errormsg,$blockcount,$readonly);
     }      }
     &display_addblocker_table($r,$parmcount,\%ltext);      unless ($readonly) {
     my $end_page=&Apache::loncommon::end_page();          $r->print(<<"END");
     $r->print(<<"END");  
 <br />  <br />
 <input type="hidden" name="blocktotal" value="$blockcount" />  
 <input type ="submit" value="$lt{'stor'}" />  <input type ="submit" value="$lt{'stor'}" />
 </form>  
 $end_page  
 END  END
       }
     $r->print(&Apache::loncommon::end_page());      $r->print('</form>'.
                 &Apache::loncommon::end_page());
     return OK;      return OK;
 }  }
   
   sub get_permission {
       my %permission;
       my $allowed = 0;
       my $readonly = 0;
       return ($readonly,$allowed) unless ($env{'request.course.id'});
       if ((&Apache::lonnet::allowed('dcm',$env{'request.course.id'})) ||
           (&Apache::lonnet::allowed('dcm',$env{'request.course.id'}.'/'.
                     $env{'request.course.sec'}))) {
           $allowed = 1;
       } elsif ((&Apache::lonnet::allowed('vcb',$env{'request.course.id'})) ||
                (&Apache::lonnet::allowed('vcb',$env{'request.course.id'}.'/'.
                     $env{'request.course.sec'}))) {
           $readonly = 1;
           $allowed = 1;
       }
       return ($readonly,$allowed);
   }
   
   sub get_timed_items {
       my ($cdom,$cnum) = @_;
       my ($cid,%intervals);
       if ($cdom eq '' || $cnum eq '') {
           $cid = $env{'request.course.id'};
           $cdom = $env{'course.'.$cid.'.domain'};
           $cnum = $env{'course.'.$cid.'.num'};
       } else {
           $cid = $cdom.'_'.$cnum;
       }
       if ($cid eq '') {
           return %intervals;
       }
       my $resourcedata=&Apache::lonparmset::readdata($cnum,$cdom);
       if (ref($resourcedata) eq 'HASH') {
           foreach my $key (keys(%{$resourcedata})) {
               if ($key =~ /^\Q$cid\E(.*)\.0\.interval$/) {
                   my $middle = $1;
                   if ($middle eq '') {
                       $intervals{'course'}{'all'} = $resourcedata->{$key};
                   } elsif ($middle =~ /^\.\[(\w+)\]$/) {
                       $intervals{'course'}{'secgrp'}{$1} = $resourcedata->{$key};
                   } elsif ($middle =~ /^\.\[useropt\:($match_username\:$match_domain)\]$/) {
                       $intervals{'course'}{'users'}{$1} = $resourcedata->{$key};
                   } elsif ($middle =~ /^\.(.+)\Q___(all)\E$/) {
                       my $inner = $1;
                       if ($inner =~ /^\[(\w+)\]\.([^\]]+)$/) {
                           $intervals{'map'}{$2}{'secgrp'}{$1} = $resourcedata->{$key};
                       } elsif ($inner =~ /^\[useropt\:($match_username\:$match_domain)\]\.([^\]]+)$/) {
                           $intervals{'map'}{$2}{'users'}{$1} = $resourcedata->{$key};
                       } else {
                           $intervals{'map'}{$inner}{'all'} = $resourcedata->{$key};
                       }
                   } elsif ($middle =~ /^\.\[(\w+)\]\.([^\]]+)$/) {
                       $intervals{'resource'}{$2}{'secgrp'}{$1} = $resourcedata->{$key}; 
                   } elsif ($middle =~ /^\.\[useropt\:($match_username\:$match_domain)\]\.([^\]]+)$/) {
                       $intervals{'resource'}{$2}{'users'}{$1} = $resourcedata->{$key};
                   } else {
                       my ($symb) = ($middle =~ /^\.(.+)$/);
                       $intervals{'resource'}{$symb}{'all'} = $resourcedata->{$key};
                   }
               }
           }
       }
       return %intervals;
   }
   
 sub blockstore {  sub blockstore {
     my $r = shift;      my ($r,$crstype,$blockcount,$currblockrecs) = @_;
     my %lt=&Apache::lonlocal::texthash(      my %lt=&Apache::lonlocal::texthash(
             'tfcm' => 'The following changes were made',              'tfcm' => 'The following changes were made',
             'ncwm' => 'No changes were made.'              'ncwm' => 'No changes were made.',
               'unna' => 'Unable to retrieve contents of course.', 
     );      );
     my %adds = ();      my %adds = ();
     my %removals = ();      my %removals = ();
Line 202  sub blockstore { Line 771  sub blockstore {
     my $modtotal = 0;      my $modtotal = 0;
     my $canceltotal = 0;      my $canceltotal = 0;
     my $addtotal = 0;      my $addtotal = 0;
       my $changestotal = 0;
       my $addtimer = 0;
     my %blocking = ();      my %blocking = ();
     $r->print('<h3>'.$lt{'head'}.'</h3>');      my (%map_url,%resource_symb,%titles,$output);
     foreach my $envkey (keys(%env)) {      $output = '<h3>'.$lt{'head'}.'</h3>';
         if ($envkey =~ m/^form\.modify_(\d+)$/) {      if ($env{'form.blockaction'} eq 'modify') {
             $adds{$1} = $1;          foreach my $envkey (keys(%env)) {
             $removals{$1} = $1;              if ($envkey =~ m/^form\.action_(\d+)$/) {
             $modtotal ++;                  if ($env{$envkey} eq 'modify') {
         } elsif ($envkey =~ m/^form\.cancel_(\d+)$/) {                      $adds{$1} = 1;
             $cancels{$1} = $1;                      $removals{$1} = 1;
             unless ( defined($removals{$1}) ) {                  } elsif ($env{$envkey} eq 'cancel') {
                 $removals{$1} = $1;                      $cancels{$1} = $1;
                 $canceltotal ++;                      unless ( defined($removals{$1}) ) {
             }                          $removals{$1} = 1;
         } elsif ($envkey =~ m/^form\.add_(\d+)$/) {                          $canceltotal ++;
             $adds{$1} = $1;                      }
             $addtotal ++;                  }
               }
         }          }
       } elsif ($env{'form.blockaction'} eq 'add') {
           $adds{$blockcount} = 1;
     }      }
       my ($navmap,$errormsg) =
           &Apache::loncourserespicker::get_navmap_object($crstype,'examblock');
       unless (ref($navmap)) {
           $output = $lt{'unna'}.' '.$lt{'ncwm'}.'</br>';
           return ($changestotal,$output);
       }
       &Apache::loncourserespicker::enumerate_course_contents($navmap,\%map_url,\%resource_symb,\%titles,'examblock');
       my $do_releasereq_update;
       my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
       my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
       my $chome = $env{'course.'.$env{'request.course.id'}.'.home'};
       my $chostname = &Apache::lonnet::hostname($chome);
       my ($chomemajor,$chomeminor) =
           split(/\./,&Apache::lonnet::get_server_loncaparev($cdom,$chome));
   
   
     foreach my $key (keys(%removals)) {      foreach my $key (keys(%removals)) {
         my $hashkey = $env{'form.key_'.$key};          my $hashkey = $env{'form.key_'.$key};
         &Apache::lonnet::del('comm_block',["$hashkey"],          if ($hashkey =~ /firstaccess____/) {
                          $env{'course.'.$env{'request.course.id'}.'.domain'},             $do_releasereq_update = 1;
                          $env{'course.'.$env{'request.course.id'}.'.num'}          }
                          );          if (ref($currblockrecs->{$hashkey}) eq 'HASH') {
               if (ref($currblockrecs->{$hashkey}->{'blocks'}) eq 'HASH') {
                   foreach my $type ('docs','printout') {
                       if (exists($currblockrecs->{$hashkey}->{'blocks'}->{$type})) {
                           $do_releasereq_update = 1;
                       }
                   }
               }
           }
           &Apache::lonnet::del('comm_block',["$hashkey"],$cdom,$cnum);
       }
       if ($do_releasereq_update) {
           push(@{$modified_courses},[$cdom,$cnum,$chome,$crstype]);
           unless ($registered_cleanup) {
               my $handlers = $r->get_handlers('PerlCleanupHandler');
               $r->set_handlers('PerlCleanupHandler' => [\&update_releasereq,@{$handlers}]);
               $registered_cleanup=1;
           }
     }      }
     foreach my $key (keys(%adds)) {      foreach my $key (keys(%adds)) {
         unless ( defined($cancels{$key}) ) {          unless ( defined($cancels{$key}) ) {
             my ($newstart,$newend) = &get_dates_from_form($key);              my ($newkey,$status,$needsrelease);;
             my $newkey = $newstart.'____'.$newend;              if ($env{'form.firstaccess_'.$key}) {
             my $blocktypes = &get_block_choices($key);                  my $interval = 
             $blocking{$newkey} = {                      &HTML::Entities::decode($env{'form.firstaccess_'.$key});
                   if ($interval ne '') {
                       if ($interval eq 'course') {
                           $newkey = 'firstaccess____'.$interval;
                       } elsif ($interval =~ /___\d+___/) {
                           my ($map,$resid,$url) = 
                               &Apache::lonnet::decode_symb($interval);
                           if (&Apache::lonnet::is_on_map($url)) {
                               $newkey = 'firstaccess____'.$interval;
                           }
                       } elsif (&Apache::lonnet::is_on_map($interval)) {
                           $newkey = 'firstaccess____'.$interval;
                       }
                       if ($newkey ne '') {
                           unless (defined($removals{$key})) {
                               ($status,$needsrelease) = &check_release_required('timer',$chomemajor,$chomeminor);
                               if ($status eq 'fail') {
                                   $newkey = '';
                                   $output .= '<p class="LC_warning">'.
                                              &mt('Triggering of blocking events not allowed for [_1]',
                                                  &escape($env{'form.title_'.$key})).'<br />';
                               }
                           }
                       }
                   }
               } else {
                   my ($newstart,$newend) = &get_dates_from_form($key);
                   $newkey = $newstart.'____'.$newend;
               }
               if ($status eq 'fail') {
                   $output .=  &mt('LON-CAPA version ([_1]) installed on home server ([_2]) does not meet version requirements ([_3] or newer).',
                                   $chomemajor.'.'.$chomeminor,$chostname,$needsrelease).'</p>';
               }
               if ($newkey ne '') {
                   my ($blocktypes,$blockdocs) = 
                       &get_block_choices($key,\%map_url,\%resource_symb);
                   if (ref($blocktypes) eq 'HASH') {
                       if ($blocktypes->{'printout'} eq 'on') {
                           ($status,$needsrelease) = &check_release_required('printout',$chomemajor,$chomeminor);
                           if ($status eq 'fail') {
                               $blocktypes->{'printout'} = 'off';
                               $output .= '<p class="LC_warning">'.
                                          &mt('Printout blocking not allowed for [_1]',
                                              &escape($env{'form.title_'.$key})).'<br />';
                           }
                       }
                       if ($blocktypes->{'alert'} eq 'on') {
                           ($status,$needsrelease) = &check_release_required('alert',$chomemajor,$chomeminor);
                           if ($status eq 'fail') {
                               $blocktypes->{'alert'} = 'off';
                               $output .= '<p class="LC_warning">'.
                                          &mt('Message Alert blocking not allowed for [_1]',
                                              &escape($env{'form.title_'.$key})).'<br />';
                           }
                       }
                       if ($blocktypes->{'reinit'} eq 'on') {
                           ($status,$needsrelease) = &check_release_required('reinit',$chomemajor,$chomeminor);
                           if ($status eq 'fail') {
                               $blocktypes->{'reinit'} = 'off';
                               $output .= '<p class="LC_warning">'.
                                          &mt('Course Re-initialization blocking not allowed for [_1]',
                                              &escape($env{'form.title_'.$key})).'<br />';
                           }
                       }
                   }
                   if ($blockdocs) {
                       ($status,$needsrelease) = &check_release_required('docs',$chomemajor,$chomeminor);
                       if ($status eq 'fail') {
                           delete($blocktypes->{'docs'});
                           $output .= '<p class="LC_warning">'.
                                      &mt('Content blocking not allowed for [_1]',
                                          &escape($env{'form.title_'.$key})).'<br />';
                       }
                   }
                   $blocking{$newkey} = {
                           setter => $env{'user.name'}.':'.$env{'user.domain'},                            setter => $env{'user.name'}.':'.$env{'user.domain'},
                           event  => &escape($env{'form.title_'.$key}),                            event  => &escape($env{'form.title_'.$key}),
                           blocks => $blocktypes,                            blocks => $blocktypes,
                         };                          };
                   if (exists($removals{$key})) {
                       $modtotal ++;
                   } else {
                       $addtotal ++;
                   }
               } else {
                   if ($env{'form.toggle_'.$key} eq 'timer') {
                       unless ($status eq 'fail') {
                           $output .= '<p class="LC_warning">'.
                                      &mt('Invalid trigger for new blocking event').
                                      '</p>';
                       }
                   } else {
                       $output .= '<p class="LC_warning">'.
                                  &mt('No date range found for new blocking event').
                                  '</p>';
                   }
               }
         }          }
     }      }
     if ($addtotal + $modtotal > 0) {      if ($addtotal + $modtotal > 0) {
Line 246  sub blockstore { Line 944  sub blockstore {
                      $env{'course.'.$env{'request.course.id'}.'.num'}                       $env{'course.'.$env{'request.course.id'}.'.num'}
                      );                       );
     }      }
     my $chgestotal = $canceltotal + $modtotal + $addtotal;      $changestotal = $canceltotal + $modtotal + $addtotal;
     if ($chgestotal > 0) {      if ($changestotal > 0) {
         $r->print($lt{'tfcm'}.'<ul>');          &Apache::lonnet::devalidate_cache_new('comm_block',
                                                 $env{'request.course.id'});
           $output .= $lt{'tfcm'}.'<ul>';
         if ($canceltotal > 0) {          if ($canceltotal > 0) {
             $r->print('<li>'.&mt('[quant,_1,communication blocking period was,communication blocking periods were] removed.',$canceltotal).'</li>');              $output .= '<li>'.
                          &mt('[quant,_1,blocking event was,blocking events were] removed.',
                              $canceltotal).
                          '</li>';
         }          }
         if ($modtotal > 0) {          if ($modtotal > 0) {
             $r->print('<li>'.&mt('[quant,_1,communication blocking period was,communication blocking periods were] modified.',$modtotal).'</li>');              $output .= '<li>'.
                          &mt('[quant,_1,blocking event was,blocking events were] modified.',
                              $modtotal).
                          '</li>';
         }          }
         if ($addtotal > 0) {          if ($addtotal > 0) {
             $r->print('<li>'.&mt('[quant,_1,communication blocking period was,communication blocking periods were] added.',$addtotal).'</li>');              $output .= '<li>'.
                          &mt('[quant,_1,blocking event was,blocking events were] added.',
                              $addtotal).
                          '</li>';
         }          }
         $r->print('</ul>');          $output .= '</ul>';
     } else {      } else {
         $r->print($lt{'ncwm'});          $output .= $lt{'ncwm'};
       }
       $output .= '<br />';
       return ($changestotal,$output);
   }
   
   sub update_releasereq {
       my $readmap = 1;
       my $getrelreq = 1;
       if (ref($modified_courses) eq 'ARRAY') {
           foreach my $item (@{$modified_courses}) {
               if (ref($item) eq 'ARRAY') {
                   my ($cdom,$cnum,$chome,$crstype) = @{$item};
                   &Apache::lonrelrequtils::modify_course_relreq(undef,undef,$cnum,$cdom,
                                                                 $chome,$crstype,$cdom.'_'.$cnum,
                                                                 $readmap,$getrelreq);
               }
           }
           $modified_courses = [];
     }      }
     $r->print('<br />');      undef($registered_cleanup);
     return;      return;
 }  }
   
Line 274  sub get_dates_from_form { Line 1001  sub get_dates_from_form {
 }  }
   
 sub get_blockdates {  sub get_blockdates {
     my ($records,$blockcount) = @_;      my ($records) = @_;
     $$blockcount = 0;      my $blockcount = 0;
     %{$records} = &Apache::lonnet::dump('comm_block',      %{$records} = &Apache::lonnet::dump('comm_block',
                          $env{'course.'.$env{'request.course.id'}.'.domain'},                           $env{'course.'.$env{'request.course.id'}.'.domain'},
                          $env{'course.'.$env{'request.course.id'}.'.num'}                           $env{'course.'.$env{'request.course.id'}.'.num'}
                          );                           );
     $$blockcount = keys(%{$records});      $blockcount = keys(%{$records});
   
     if ((keys(%{$records}))[0] =~ /^error: 2 /) {      if ((keys(%{$records}))[0] =~ /^error: 2 /) {
         $$blockcount = 0;          $blockcount = 0;
     }      }
       return $blockcount;
 }  }
   
 sub get_block_choices {  sub get_block_choices {
     my $item = shift;      my ($item,$map_ref,$symb_ref) = @_;
     my $blocklist;      my $blocklist;
       my $blockdocs;
     my ($typeorder,$types) = &blocktype_text();      my ($typeorder,$types) = &blocktype_text();
     foreach my $type (@{$typeorder}) {      foreach my $type (@{$typeorder}) {
         if ($env{'form.'.$type.'_'.$item}) {          if ($type eq 'docs') {
             $blocklist->{$type} = 'on';              if ($env{'form.'.$type.'_'.$item}) {
                   $blocklist->{$type} = {};
                   if ($env{'form.docs_resources_'.$item}) {
                       $env{'form.docs_resources_'.$item} =~ s/,$//;
                       if (ref($symb_ref) eq 'HASH') {
                           my %resources = map { $symb_ref->{$_} => 1; } 
                                               (split(/,/,$env{'form.docs_resources_'.$item}));
                           if (exists($resources{''})) {
                               delete($resources{''});
                           }
                           $blocklist->{$type}->{resources} = \%resources;
                           if (keys(%resources) > 0) {
                               $blockdocs = 1;
                           }
                       }
                   }
                   if ($env{'form.docs_maps_'.$item}) {
                       $env{'form.docs_maps_'.$item} =~ s/,$//;
                       if (ref($map_ref) eq 'HASH') {
                           my %maps = map { $map_ref->{$_} => 1; }                             
                                          (split(/,/,$env{'form.docs_maps_'.$item}));
                           if (exists($maps{''})) {
                               delete($maps{''});
                           }
                           $blocklist->{$type}->{maps} = \%maps;
                           if (keys(%maps) > 0) {
                               $blockdocs = 1;
                           }
                       }
                   }
               }
           } else {
               if ($env{'form.'.$type.'_'.$item}) {
                   $blocklist->{$type} = 'on';
               } else {
                   $blocklist->{$type} = 'off';
               }
           }
       }
       return ($blocklist,$blockdocs);
   }
   
   sub check_release_required {
       my ($value,$chomemajor,$chomeminor) = @_; 
       my $needsrelease = $Apache::lonnet::needsrelease{'course:commblock:'.$value};
       if ($needsrelease) {
           my ($needsmajor,$needsminor) = split(/\./,$needsrelease);
           if (($chomemajor < $needsmajor) || 
               (($chomemajor == $needsmajor) && ($chomeminor < $needsminor))) {
               return ('fail',$needsrelease);
           }
           my $curr_required =
               $env{'course.'.$env{'request.course.id'}.'.internal.releaserequired'};
           if ($curr_required eq '') {
               &Apache::lonnet::update_released_required($needsrelease);
         } else {          } else {
             $blocklist->{$type} = 'off';              my ($currmajor,$currminor) = split(/\./,$curr_required);
               my ($needsmajor,$needsminor) = split(/\./,$needsrelease);
               if (($currmajor < $needsmajor) || 
                   ($currmajor == $needsmajor && $currminor < $needsminor)) {
                   &Apache::lonnet::update_released_required($needsrelease);
               }
         }          }
     }      }
     return $blocklist;      return ('ok',$needsrelease);
 }  }
   
 sub display_blocker_status {  sub display_blocker_status {
     my ($r,$records,$ltext) = @_;      my ($r,$records,$ltext,$intervals,$navmap,$errormsg,$blockcount,$readonly) = @_;
     my $parmcount = 0;      my $parmcount = 0;
        my (%map_url,%resource_symb,%titles,%lookups,$disabled);
       &Apache::loncourserespicker::enumerate_course_contents($navmap,\%map_url,\%resource_symb,\%titles,'examblock');
       %{$lookups{'maps'}} = reverse(%map_url);
       %{$lookups{'resources'}} = reverse(%resource_symb);
     my %lt = &Apache::lonlocal::texthash(      my %lt = &Apache::lonlocal::texthash(
         'modi' => 'Modify',          'modi' => 'Modify',
         'canc' => 'Cancel',          'dele' => 'Delete',
           'noch' => 'No change',
     );      );
     my ($typeorder,$types) = &blocktype_text();      $r->print('<div id="showmodify" style="display:block">'.
     $r->print(&Apache::loncommon::start_data_table());                &Apache::loncommon::start_data_table().'<tr>');
       if ($readonly) {
           $disabled = ' disabled="disabled"';
       } else {
           $r->print('<th></th>');
       }
     $r->print(<<"END");      $r->print(<<"END");
   <tr>      <th>$ltext->{'type'}</th>
     <th>$ltext->{'dura'}</th>  
     <th>$ltext->{'setb'}</th>  
     <th>$ltext->{'even'}</th>      <th>$ltext->{'even'}</th>
     <th>$ltext->{'blck'}</th>      <th>$ltext->{'blck'}</th>
     <th>$ltext->{'actn'}</th>  
   </tr>    </tr>
 END  END
     foreach my $record (sort(keys(%{$records}))) {      foreach my $record (sort(keys(%{$records}))) {
         my $onchange = 'onFocus="javascript:window.document.forms['.          my $jschg = 
                        "'blockform'].elements['modify_".$parmcount."'].".              'javascript:window.document.forms['. "'blockform'".']'.
                        'checked=true;"';              '.elements['."'action_$parmcount'".'][0].checked=true;';
         my ($start,$end) = split(/____/,$record);          my $onchange = 'onfocus="'.$jschg.'"';
         my $startform = &Apache::lonhtmlcommon::date_setter('blockform','startdate_'.$parmcount,$start,$onchange);  
         my $endform = &Apache::lonhtmlcommon::date_setter('blockform','enddate_'.$parmcount,$end,$onchange);  
   
         my ($setuname,$setudom,$title,$blocks) =          my ($setuname,$setudom,$title,$blocks) =
             &Apache::loncommon::parse_block_record($$records{$record});              &Apache::loncommon::parse_block_record($$records{$record});
         $title = &HTML::Entities::encode($title,'"<>&');          $title = &HTML::Entities::encode($title,'"<>&');
           my $blockid = &HTML::Entities::encode($record,'"<>&');
         my $settername =          my $settername =
            &Apache::loncommon::aboutmewrapper(             &Apache::loncommon::aboutmewrapper(
                            &Apache::loncommon::plainname($setuname,$setudom),                             &Apache::loncommon::plainname($setuname,$setudom),
                            $setuname,$setudom);                             $setuname,$setudom);
           my $state = '';
         $r->print(&Apache::loncommon::start_data_table_row());          $r->print(&Apache::loncommon::start_data_table_row());
         $r->print(<<"END");          if ($readonly) {
         <td>$ltext->{'star'}:&nbsp;$startform<br />$ltext->{'endd'}:&nbsp;&nbsp;$endform</td>              $state = 'disabled';
         <td>$settername</td>          } else {
         <td><input type="text" name="title_$parmcount" size="15" value="$title" /><input type="hidden" name="key_$parmcount" value="$record" /></td>              $r->print(<<"ACT");
         <td>  
 END          <td valign="middle"><span class="LC_nobreak"><label>
         foreach my $block (@{$typeorder}) {          <input type="radio" name="action_$parmcount" value="modify" />$lt{'modi'}
             my $blockstatus = '';          </label></span><br />
             if ($blocks->{$block} eq 'on') {          <span class="LC_nobreak"><label>
                 $blockstatus = 'checked="checked"';          <input type="radio" name="action_$parmcount" value="cancel" />$lt{'dele'}
           </label></span><br />
           <span class="LC_nobreak"><label>
           <input type="radio" name="action_$parmcount" id="nochange_$parmcount" 
            value="nochange" checked="checked" />$lt{'noch'}
           </label></span>
           </td>
   ACT
           }
           my ($start,$end,$startform,$endform); 
           if ($record =~ /^(\d+)____(\d+)$/) {
               ($start,$end) = split(/____/,$record);
               $startform = &Apache::lonhtmlcommon::date_setter('blockform','startdate_'.
                                                                $parmcount,$start,$onchange,
                                                                undef,$state);
               $endform = &Apache::lonhtmlcommon::date_setter('blockform','enddate_'.
                                                              $parmcount,$end,$onchange,
                                                              undef,$state);
               $r->print('<td><fieldset><legend>'.$ltext->{'defs'}.'</legend>'.
                         $ltext->{'star'}.':&nbsp;'.$startform.'<br />'.
                         $ltext->{'endd'}.':&nbsp;&nbsp;'.$endform.'</fieldset></td>');
           } elsif ($record =~ /^firstaccess____(.+)$/) {
               my $item = $1;
               my $type = 'map';
               my $url;
               if ($item eq 'course') {
                   $type = 'course';
               } elsif ($item =~ /___\d+___/) {
                   $type = 'resource';
                   (my $map, my $resid, $url) = &Apache::lonnet::decode_symb($item);  
               } else {
                   $url = $item;
             }              }
             $r->print('<span class="LC_nobreak"><label><input type="checkbox" name="'.$block.'_'.$parmcount.'" '.$blockstatus.' value="1" />'.$types->{$block}.'</label></span><br />');              $r->print('<td><fieldset><legend>'.$ltext->{'trig'}.'</legend>');
               my ($itemname,$iteminfo) = &interval_details($item,$type,$url,$navmap,$intervals,$parmcount);
               $r->print(&create_interval_form($intervals,$parmcount,$navmap,'blocking',$item,$jschg,
                                               $itemname,$iteminfo,$disabled).'</fieldset></td>');
         }          }
         $r->print(<<"END");          $r->print(<<"END");
         </td>           <td>
         <td><span class="LC_nobreak"><label>           <input type="text" name="title_$parmcount" size="15" value="$title" onfocus="$jschg" $disabled />
         <input type="checkbox" name="modify_$parmcount" />$lt{'modi'}           <input type="hidden" name="key_$parmcount" value="$blockid" />
         </label></span><br /><span class="LC_nobreak">           <br />
         <label>           <br />
         <input type="checkbox" name="cancel_$parmcount" />$lt{'canc'}           $ltext->{'setb'}: $settername
         </label></span>          </td>
 END  END
         $r->print(&Apache::loncommon::end_data_table_row());          $r->print('<td>'.&blocker_checkboxes($parmcount,$blocks,$jschg,\%lookups,$disabled).'</td>'.
                     &Apache::loncommon::end_data_table_row());
         $parmcount++;          $parmcount++;
     }      }
     $r->print(<<"END");      $r->print(<<"END");
 </table>  </table>
 <br />  </div>
 <br />  
 END  END
     return $parmcount;      return;
   }
   
   sub convlim {
       my ($timelimit) = @_;
       my @order = ('days','hours','minutes','seconds');
       my %catlimits = ( 
                         days    => 86400,
                         hours   => 3600,
                         minutes => 60,
                       );
       my @toshow;
       foreach my $cat (@order) {
           if ($cat eq 'seconds') {
               if ($timelimit > 0) {
                   push(@toshow,&mt("[_1] $cat",$timelimit));
               }
           } elsif ($timelimit >= $catlimits{$cat}) {
               my $val = int($timelimit/$catlimits{$cat});
               if ($val > 0) {
                   push(@toshow,&mt("[_1] $cat",$val));
               }
               $timelimit -= $val*$catlimits{$cat};
           }
       }
       my $output = join(', ',@toshow);
       return $output;
 }  }
   
 sub display_addblocker_table {  sub display_addblocker_table {
     my ($r,$parmcount,$ltext) = @_;      my ($r,$parmcount,$ltext,$intervals,$navmap,$errormsg) = @_;
       return unless ((ref($ltext) eq 'HASH') && (ref($intervals) eq 'HASH'));
     my $start = time;      my $start = time;
     my $end = $start + (60 * 60 * 2); #Default is an exam of 2 hours duration.      my $end = $start + (60 * 60 * 2); #Default is an exam of 2 hours duration.
     my $onchange = 'onFocus="javascript:window.document.forms['.      my $onchange = 'onfocus="javascript:window.document.forms['.
                    "'blockform'].elements['add_".$parmcount."'].".                     "'blockform'].elements['addaction'].".
                    'checked=true;"';                     'checked=true;"';
     my $startform = &Apache::lonhtmlcommon::date_setter('blockform','startdate_'.$parmcount,$start,$onchange);      my $startform = &Apache::lonhtmlcommon::date_setter('blockform','startdate_'.
     my $endform = &Apache::lonhtmlcommon::date_setter('blockform','enddate_'.$parmcount,$end,$onchange);                                                          $parmcount,$start,$onchange);
       my $endform = &Apache::lonhtmlcommon::date_setter('blockform','enddate_'.
                                                         $parmcount,$end,$onchange);
     my %lt = &Apache::lonlocal::texthash(      my %lt = &Apache::lonlocal::texthash(
         'addb' => 'Add block',  
         'exam' => 'e.g., Exam 1',          'exam' => 'e.g., Exam 1',
         'addn' => 'Add new communication blocking periods'  
     );      );
     my ($typeorder,$types) = &blocktype_text();      my $intervalform = &create_interval_form($intervals,$parmcount,$navmap,'blocking');
     $r->print(<<"END");      if ($intervalform ne '') {
 <h4>$lt{'addn'}</h4>          $intervalform = '<fieldset>'.
 END                          '<legend>'.$ltext->{'chtr'}.'</legend>'.
                           $intervalform.
                           '</fieldset>';
       }
     $r->print(&Apache::loncommon::start_data_table());      $r->print(&Apache::loncommon::start_data_table());
     $r->print(<<"END");      $r->print(<<"END");
    <tr>     <tr>
      <th>$ltext->{'dura'}</th>       <th>$ltext->{'type'}</th>
      <th>$ltext->{'even'} $lt{'exam'}</th>       <th>$ltext->{'even'} $lt{'exam'}</th>
      <th>$ltext->{'blck'}</th>       <th>$ltext->{'blck'}</th>
      <th>$ltext->{'actn'}</th>  
    </tr>     </tr>
 END  END
     $r->print(&Apache::loncommon::start_data_table_row());      $r->print(&Apache::loncommon::start_data_table_row().'<td>');
     $r->print(<<"END");      $r->print(<<"END");
      <td>$ltext->{'star'}:&nbsp;$startform<br />$ltext->{'endd'}:&nbsp;&nbsp;$endform</td>       <span class="LC_nobreak"><label><input type="radio" id="toggle_startstop" 
      <td><input type="text" name="title_$parmcount" size="15" value="" /></td>       name="toggle_$parmcount" value="startstop" onclick="showBlockType();" checked="checked" />
      <td>       $ltext->{'defs'}</label></span>&nbsp;&nbsp; 
 END       <span class="LC_nobreak"><label><input type="radio" id="toggle_timer" name="toggle_$parmcount" 
     foreach my $block (@{$typeorder}) {       value="timer" onclick="showBlockType();" />$ltext->{'trig'}</label></span><br />
         $r->print('<span class="LC_nobreak"><label><input type="checkbox" name="'.$block.'_'.$parmcount.'" value="1" />'.$types->{$block}.'</label></span><br />');       <div id="show_startstop" style="display:block">
      }       <fieldset><legend>$ltext->{'chda'}</legend>
      $r->print(<<"END");       $ltext->{'star'}:&nbsp;$startform<br />$ltext->{'endd'}:&nbsp;&nbsp;$endform</fieldset>
        <span class="LC_warning">$ltext->{'when'}</span></div>
        <div id="show_timer" style="display:none">$intervalform</div>
      </td>       </td>
      <td><span class="LC_nobreak"><label>       <td><input type="text" name="title_$parmcount" size="15" value="" /></td>
      <input type="checkbox" name="add_$parmcount" value="1" />$lt{'addb'}  
      </label></span></td>  
 END  END
     $r->print(&Apache::loncommon::end_data_table_row());      $r->print('<td>'.&blocker_checkboxes($parmcount).'</td>'.
     $r->print(&Apache::loncommon::end_data_table());                &Apache::loncommon::end_data_table_row().
                 &Apache::loncommon::end_data_table()."\n".
                 '<br />');
       return;
   }
   
   sub blocker_checkboxes {
       my ($parmcount,$blocks,$jschg,$lookups,$disabled) = @_;
       my ($typeorder,$types) = &blocktype_text();
       my $numinrow = 2;
       my %currdocs;
       my $output = '<table>';
       for (my $i=0; $i<@{$typeorder}; $i++) {
           my $block = $typeorder->[$i];
           my ($clickaction,$blockstatus);
           if ($jschg) {
               $clickaction = $jschg;
           } 
           if ($block eq 'docs') {
               if ((ref($blocks) eq 'HASH') && (ref($lookups) eq 'HASH')) {
                   if (ref($blocks->{$block}) eq 'HASH') {
                       if (keys(%{$blocks->{$block}}) > 0) {
                           $blockstatus = 'checked="checked"';
                           foreach my $key (sort(keys(%{$blocks->{$block}}))) {
                               if (ref($blocks->{$block}{$key}) eq 'HASH') {
                                   my @current = ();
                                   foreach my $item (keys(%{$blocks->{$block}{$key}})) {
                                       if ($lookups->{$key}{$item}) {
                                           push(@current,$lookups->{$key}{$item});
                                       }
                                   }
                                   if (@current > 0) {
                                       @current=sort { $a <=> $b } (@current);
                                       $currdocs{$key} = join(',',@current);
                                   }
                               }
                           }
                       }
                   }
               }
               $clickaction .= 'javascript:resblockinfo('."'$parmcount'".');';
           } else {
               if (ref($blocks) eq 'HASH') { 
                   if ($blocks->{$block} eq 'on') {
                       $blockstatus = 'checked="checked"';
                   }
               }
           }
           my $rem = $i%($numinrow);
           if ($rem == 0) {
               if ($i > 0) {
                   $output .= '</tr>';
               }
               $output .= '<tr>';
           }
           if ($i == scalar(@{$typeorder})-1) {
               my $colsleft = $numinrow-$rem;
               if ($colsleft > 1) {
                   $output .= '<td colspan="'.$colsleft.'">';
               } else {
                   $output .= '<td>';
               }
           } else {
               $output .= '<td>';
           }
           my $item = $block.'_'.$parmcount;
           if ($clickaction) {
               $clickaction = ' onclick="'.$clickaction.'"';
           }
           if ($blockstatus) {
               $blockstatus = ' '.$blockstatus;
           } 
           $output .= '<span class="LC_nobreak"><label>'."\n".
                      '<input type="checkbox" id="'.$item.'" name="'.$item.'"'.
                      $blockstatus.$clickaction.' value="1"'.$disabled.' />'.
                      $types->{$block}.'</label></span>'."\n";
           if ($block eq 'docs') {
               if ($blockstatus ne '') {
                   $output .= '&nbsp;<a href="javascript:resblockinfo('."'$parmcount'".')">'.
                               &mt('Details').'</a>';
               }
           }
           $output .= '<br /></td>';
       }
       $output .= '</tr></table>'.
                  '<input type="hidden" name="docs_maps_'.$parmcount.'"'.
                  ' id="docs_maps_'.$parmcount.'" value="'.$currdocs{'maps'}.'" />'.
                  '<input type="hidden" name="docs_resources_'.$parmcount.'"'.
                  ' id="docs_resources_'.$parmcount.'" value="'.$currdocs{'resources'}.'" />';
       return $output;
   }
   
   sub create_interval_form {
       my ($intervals,$parmcount,$navmap,$context,$currkey,$jschg,$itemname,$iteminfo,$disabled) = @_;
       return unless ((ref($intervals) eq 'HASH') && (ref($navmap)));
       my $intervalform;
       my $counter = 0;
       if (keys(%{$intervals}) > 0) {
           foreach my $type (sort(keys(%{$intervals}))) {
               if ($type eq 'course') {
                   my ($checked,$clickaction);
                   if ($currkey eq 'course') {
                       $checked = ' checked="checked"';
                   } elsif ($jschg) {
                       $clickaction = ' onclick="'.$jschg.'"';
                   }
                   $intervalform .= '<label><input type="radio" name="firstaccess_'.$parmcount.
                                    '" value="course"'.$checked.$clickaction.$disabled.' />';
                   if ($currkey eq 'course') {
                       $intervalform .= $itemname;
                   } else {
                       $intervalform .= &mt('Timer for all items in course');
                   }
                   $intervalform .= '</label>';
                   if ($currkey eq 'course') {
                       $intervalform .= $iteminfo;
                   } elsif ($context eq 'accesstimes') {
                       (undef,$iteminfo) = &interval_details('course',$type,'',$navmap,$intervals,$counter);
                       if ($iteminfo) {
                           $intervalform .= ' '.$iteminfo;
                       }
                   }
                   $intervalform .= '<br />';
                   $counter ++;
               } elsif ($type eq 'map') {
                   if (ref($intervals->{$type}) eq 'HASH') {
                       if (ref($navmap)) {
                           foreach my $map (sort(keys(%{$intervals->{$type}}))) {
                               next if ((!&Apache::lonnet::is_on_map($map)) &&
                                        ($currkey ne $map));
                               my ($checked,$clickaction);
                               if ($currkey eq $map) {
                                   $checked = ' checked="checked"';
                               } elsif ($jschg) {
                                   $clickaction = ' onclick="'.$jschg.'"';
                               }
                               $intervalform .= '<label><input type="radio" name="firstaccess_'.$parmcount.
                                                '" value="'.&HTML::Entities::encode($map,'"<>&').'"'.
                                                $checked.$clickaction.$disabled.' />';
                               if ($currkey eq $map) {
                                   $intervalform .= $itemname.'</label>'.$iteminfo;
                               } else {
                                   my ($resobj,$title,$path,$hierarchy);
                                   $resobj = $navmap->getResourceByUrl($map);
                                   if (ref($resobj)) {
                                       $title = $resobj->compTitle();
                                   } else {
                                       $title = &Apache::lonnet::gettitle($map);
                                   }
                                   $hierarchy = &show_timer_path($type,$map,$navmap);
                                   if ($hierarchy) {
                                       $path = ' <span style="font-size:90%;">'.
                                               &mt('(in: [_1])',$hierarchy).
                                               '</span>';
                                   }
                                   $intervalform .= &mt('Timer for all items in folder: [_1]',
                                                        '<i>'.$title.'</i>').
                                                    '</label>'.$path;
                                   if ($context eq 'accesstimes') {
                                       (undef,$iteminfo) = &interval_details($map,$type,$map,$navmap,$intervals,$counter);
                                       if ($iteminfo) {
                                           $intervalform .= ' '.$iteminfo;
                                       }
                                   }
                               }
                               $intervalform .= '<br />';
                               $counter ++;
                           }
                       }
                   }
               } elsif ($type eq 'resource') {
                   if (ref($intervals->{$type}) eq 'HASH') {
                       if (ref($navmap)) {
                           foreach my $resource (sort(keys(%{$intervals->{$type}}))) {
                               my ($checked,$clickaction,$resobj);
                               if ($currkey eq $resource) {
                                   $checked = ' checked="checked"';
                               } else {
                                   $resobj = $navmap->getBySymb($resource);
                                   next unless(ref($resobj));
                                   if ($jschg) {
                                       $clickaction = ' onclick="'.$jschg.'"';
                                   }
                               }
                               $intervalform .= '<label><input type="radio" name="firstaccess_'.$parmcount.
                                                '" value="'.&HTML::Entities::encode($resource,'"<>&').'"'.
                                                $checked.$clickaction.$disabled.' />';
                               if ($currkey eq $resource) {
                                   $intervalform .= $itemname.'</label>'.$iteminfo;
                               } else {
                                   my ($title,$path,$hierarchy);
                                   if (ref($resobj)) {
                                       $title = $resobj->compTitle();
                                   }
                                   if ($title eq '') {
                                       $title = &Apache::lonnet::gettitle($resource);
                                   }
                                   $hierarchy = &show_timer_path($type,$resource,$navmap);
                                   if ($hierarchy) {
                                       $path = ' <span style="font-size:90%;">'.
                                               &mt('(in: [_1])',$hierarchy).
                                               '</span>';
                                   }
                                   $intervalform .= &mt('Timer for resource: [_1]','<i>'.$title.'</i>').
                                                    '</label>'.
                                                    $path;
                                   if ($context eq 'accesstimes') {
                                       if (ref($resobj)) {
                                           my $url = $resobj->src();
                                           if ($url eq '') {
                                               (my $map, my $resid, $url) = &Apache::lonnet::decode_symb($resource);
                                           }
                                           ($itemname,$iteminfo) = &interval_details($resource,$type,$url,$navmap,$intervals,$counter);
                                           $intervalform .= ' '.$iteminfo;
                                       }
                                   }
                               }
                               $intervalform .= '<br />';
                               $counter ++;
                           }
                       }
                   }
               }
           }
       } else {
           if ($currkey ne '') {
               $intervalform = '<input type="radio" name="firstaccess_'.$parmcount.
                               '" checked="checked" value="'.
                               &HTML::Entities::encode($currkey,'"<>&').'"'.$disabled.' />'.
                               $itemname.'<br />';
           } else {
               $intervalform = &mt('No timed items defined.').' '.
                               &mt('Use [_1]Settings[_2] to assign a timer, then return here.',
                                   '<a href="/adm/parmset">','</a>');
           }
       }
       return $intervalform;
   }
   
   sub trigger_details_toggle {
       my ($parmcount) = @_;
       return ' <span id="toggletext_'.$parmcount.'" class="LC_cusr_subheading LC_nobreak">'.
              '<a href="javascript:showTriggerDetails('."'$parmcount'".');" '.
              'style="text-decoration: none;"><b>'.&mt('(More ...)').'</b></a></span>';
   }
   
   sub interval_details {
       my ($item,$type,$url,$navmap,$intervals,$parmcount) = @_;
       my ($itemname,$iteminfo,$skipdetails);
       if ($type eq 'course') {
           $itemname = &mt('Timer for all items in course.');
       } else {
           if (&Apache::lonnet::is_on_map($url)) {
               if ($type eq 'map') {
                   if (ref($navmap)) {
                       my $title;
                       my $resobj = $navmap->getResourceByUrl($item);
                       if (ref($resobj)) {
                           $title = $resobj->compTitle();
                       } else {
                           $title = &Apache::lonnet::gettitle($item);
                       }
                       $itemname = &mt('Timer for all items in folder: [_1]',
                                       '<span style="font-style:italic">'.
                                       $title.'</span>');
                   }
               } else {
                   if (ref($navmap)) {
                       my $title;
                       my $resobj = $navmap->getBySymb($item);
                       if (ref($resobj)) {
                           $title = $resobj->compTitle();
                       } else {
                           $title = &Apache::lonnet::gettitle($item);
                       }
                       $itemname = &mt('Timer for resource: [_1]',
                                       '<span style="font-style:italic">'.
                                       $title.'</span>');
                   }
               }
               if (ref($navmap)) {
                   my $path = &show_timer_path($type,$item);
                   if ($path) {
                      $iteminfo  = ' <span style="font-size:90%;">'.
                                     &mt('(in: [_1])',$path).
                                     '</span>';
                   }
               }
           } else {
               $skipdetails = 1;
               $itemname = '<span style="LC_warning">'.
                           &mt('Timer folder/resource not in course').
                           '</span>';
           }
       }
       if ((!$skipdetails) && (ref($intervals) eq 'HASH') && (ref($intervals->{$type}) eq 'HASH')) {
           $iteminfo = &trigger_details_toggle($parmcount).
                       '<ul id="trigdetails_'.$parmcount.'" style="display:none">';
           if ($type eq 'course') {
               foreach my $scope (keys(%{$intervals->{$type}})) {
                   if ($scope eq 'all') {
                       $iteminfo .= '<li>'.&mt('All users -- time limit: [_1]',
                                    &convlim($intervals->{$type}->{$scope})).'</li>';
                   } elsif ($scope eq 'secgrp') {
                       if (ref($intervals->{$type}->{$scope}) eq 'HASH') {
                           $iteminfo .= '<li>'.&mt('Sections/groups').'<ul>';
                           foreach my $item (sort(keys(%{$intervals->{$type}->{$scope}}))) {
                               $iteminfo .= '<li>'.&mt('[_1] -- time limit: [_2]',$item,
                                            &convlim($intervals->{$type}->{$scope}->{$item})).
                                            '</li>';
                           }
                           $iteminfo .= '</ul></li>';
                       }
                   } elsif ($scope eq 'users') {
                       if (ref($intervals->{$type}->{$scope}) eq 'HASH') {
                           $iteminfo .= '<li>'.&mt('Users').'<ul>';
                           foreach my $item (sort(keys(%{$intervals->{$type}->{$scope}}))) {
                               $iteminfo .= '<li>'.&mt('[_1] -- time limit: [_2]',
                                            &convlim($item,$intervals->{$type}->{$scope}->{$item})).
                                            '</li>';
                           }
                           $iteminfo .= '</ul></li>';
                       }
                   }
               }
           } elsif (($type eq 'map') || ($type eq 'resource')) {
               if (ref($intervals->{$type}->{$item}) eq 'HASH') {
                   foreach my $scope (keys(%{$intervals->{$type}->{$item}})) {
                       if ($scope eq 'all') {
                           $iteminfo .= '<li>'.&mt('All users -- time limit: [_1]',
                                        &convlim($intervals->{$type}->{$item}->{$scope})).
                                        '</li>';
                       } elsif ($scope eq 'secgrp') {
                           if (ref($intervals->{$type}->{$item}->{$scope}) eq 'HASH') {
                               $iteminfo .= '<li>'.&mt('Sections/groups').'<ul>';
                               foreach my $sec (sort(keys(%{$intervals->{$type}->{$item}->{$scope}}))) {
                                   $iteminfo .= '<li>'.&mt('[_1] -- time limit: [_2]',$sec,
                                                &convlim($intervals->{$type}->{$item}->{$scope}->{$sec})).
                                               '</li>';
                               }
                               $iteminfo .= '</ul></li>';
                           }
                       } elsif ($scope eq 'users') {
                           if (ref($intervals->{$type}->{$item}->{$scope}) eq 'HASH') {
                               $iteminfo .= '<li>'.&mt('Users').'<ul>';
                               foreach my $user (sort(keys(%{$intervals->{$type}->{$item}->{$scope}}))) {
                                   $iteminfo .= '<li>'.&mt('[_1] -- time limit: [_2]',$user,
                                                &convlim($intervals->{$type}->{$item}->{$scope}->{$user})).
                                                '</li>';
                               }
                               $iteminfo .= '</ul></li>';
                           }
                       }
                   }
               }
           }
           $iteminfo .= '</ul>';
       }
       return ($itemname,$iteminfo);
   }
   
   sub show_timer_path {
       my ($type,$item,$navmap) = @_;
       return unless(ref($navmap));
       my @pathitems;
       if ($type eq 'map') {
           @pathitems = 
               &Apache::loncommon::get_folder_hierarchy($navmap,$item);
       } elsif ($type eq 'resource') {
           my ($map,$id,$resource) = &Apache::lonnet::decode_symb($item);
           @pathitems = 
               &Apache::loncommon::get_folder_hierarchy($navmap,$map,1);
       }
       if (@pathitems) {
           return join(' &raquo; ',@pathitems);
       }
     return;      return;
 }  }
   
Line 424  sub blocktype_text { Line 1655  sub blocktype_text {
         'port' => 'Portfolio',          'port' => 'Portfolio',
         'groups' => 'Groups',          'groups' => 'Groups',
         'blogs' => 'Blogs',          'blogs' => 'Blogs',
           'about' => 'User Information',
           'docs' => 'Content',
           'printout' => 'Printouts',
           'passwd' => 'Change Password',
           'grades' => 'Gradebook',
           'search' => 'Content Search',
           'alert'  => 'Critical Alert',
           'reinit' => 'Course Re-init',
     );      );
     my $typeorder = ['com','chat','boards','port','groups','blogs'];      my $typeorder = ['com','chat','boards','port','groups','blogs','about','printout','docs','grades','search','alert','reinit','passwd'];
     return ($typeorder,\%types);      return ($typeorder,\%types);
 }  }
   
   sub blockingmenu_javascript {
       my ($blockcount) = @_;
       return <<ENDSCRIPT;
   <script type="text/javascript">
   // <![CDATA[
   function resblockinfo(blockid) {
       if (document.getElementById('docs_'+blockid).checked) {
           var resblockwin = null;
           var url = '/adm/setblock?action=showdocs&block='+blockid;
           if (!resblockwin || resblockwin.closed) {
               resblockwin=window.open(url,'blockingwin','height=480,width=600,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no');
           }
           resblockwin.focus();
       } else {
           document.getElementById('docs_resources_'+blockid).value = '';
           document.getElementById('docs_maps_'+blockid).value = '';
       }
       return;
   }
   
   function showBlockType() {
       if (document.getElementById('toggle_startstop').checked == true) {
           document.getElementById('show_startstop').style.display='block';
       } else {
           document.getElementById('show_startstop').style.display='none';
       }
       if (document.getElementById('toggle_timer').checked == true) {
           document.getElementById('show_timer').style.display='block';
       } else {
           document.getElementById('show_timer').style.display='none';
       }
       return;
   }
   
   function toggleAddModify() {
       for (var i=0; i<document.blockform.blockaction.length; i++) {
           if (document.blockform.blockaction[i].checked) {
               if (document.blockform.blockaction[i].value == 'add') {
                  document.getElementById('showadd').style.display='block';
                  document.getElementById('showmodify').style.display='none';
                  var blocktotal = $blockcount;
                  if (blocktotal > 0) {
                      for (var i=0; i<blocktotal; i++) {
                          document.getElementById('nochange_'+i).checked = true;
                      }
                  }
                  document.getElementById('showmodify').style.display='none';
                  document.getElementById('showadd').style.display='block';
               } else {
                  document.getElementById('showadd').style.display='none';
                  document.getElementById('showmodify').style.display='block';
               }
           }
       }
       return;
   }
   
   // ]]>
   </script>
   ENDSCRIPT
   
   }
   
   sub details_javascript {
       my %lt = &Apache::lonlocal::texthash (
                                              more => 'More ...',
                                              less => 'Less ...',
                                            );
       return <<ENDSCRIPT;
   
   <script type="text/javascript">
   // <![CDATA[
   
   function showTriggerDetails(item) {
       document.getElementById('trigdetails_'+item).style.display='block';
       document.getElementById('trigdetails_'+item).style.textAlign='left';
       document.getElementById('trigdetails_'+item).style.textFace='normal';
       document.getElementById('toggletext_'+item).innerHTML = '<a href="javascript:hideTriggerDetails('+item+');" style="text-decoration: none;"><b>($lt{'less'})</b></a>';
       return;
   }
   
   function hideTriggerDetails(item) {
       document.getElementById('trigdetails_'+item).style.display='none';
       document.getElementById('toggletext_'+item).innerHTML = '<a href="javascript:showTriggerDetails('+item+');" style="text-decoration: none;"><b>($lt{'more'})</b></a>';
       return;
   }
   
   // ]]>
   </script>
   ENDSCRIPT
   
   }
   
 1;  1;
   
 __END__  __END__

Removed from v.1.2  
changed lines
  Added in v.1.29


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