Diff for /loncom/interface/loncourserespicker.pm between versions 1.4 and 1.21

version 1.4, 2013/01/14 18:47:14 version 1.21, 2024/12/26 17:12:36
Line 33  loncourserespicker - Utilities to choose Line 33  loncourserespicker - Utilities to choose
   
 =head1 SYNOPSIS  =head1 SYNOPSIS
   
 loncourserespicker provides an interface for selecting which folders and/or  loncourserespicker provides either (1) an interface for selecting which 
 resources are to be either:  folders and/or resources are to be selected for a specific action, one of: 
   
 (a) exported to an IMS Content Package  (a) export to an IMS Content Package
 (b) subject to access blocking for the duriation of an exam/quiz.    (b) be subject to access blocking for the duration of an exam/quiz.
   (c) dump to an Authoring Space
   (d) receive shortened URLs to be used when deep-linking into a course
   
   or (2) an interface for selecting a single folder or resource for which 
   existing passback credentials can be used to send scores to another Course
   Management System (CMS).
   
 =head1 DESCRIPTION  =head1 DESCRIPTION
   
 This module provides routines to generate a hierarchical display of folders  This module provides routines to generate a hierarchical display of folders
 and resources in a course which can be selected for specific actions.  and resources in a course which can be selected for specific actions. In 
   all except one use case all items in the course are shown. The case where
 The choice of items is copied back to the main window from which the pop-up  only a filtered list is shown is passback of scores, and filtering limits
 window used to display the Course Contents was opened.  folders and resources to those items for which passback credentials exist,
   (and their parent folders).
   
   When the display is shown in a pop-up window, The choice of items will be
   copied back to the main window from which the pop-up window used to display
   the Course Contents was opened.
   
 =head1 OVERVIEW  =head1 OVERVIEW
   
 The main subroutine: &create_picker() will display the hierarchy of folders,  In the cases where multiple items may be selected the main subroutine:
 sub-folders, and resources in the Main Course Documents area.  Items can be  &create_picker() will display the hierarchy of folders, sub-folders, and
 selected using checkboxes, and/or a "Check All" button.  Selection of a folder  resources in the Main Content area. Items can be selected using checkboxes,
 causes the contents of the folder to also be selected automatically. The  and/or a "Check All" button.  Selection of a folder causes the contents of
 propagation of check status is recursive into sub-folders.  Likewise, if an  the folder to also be selected automatically. The propagation of check
 item deep in a nested set of folders and sub-folders is unchecked, the   status is recursive into sub-folders.  Likewise, if an item deep in a nested
 uncheck will propagate up through the hierarchy causing any folders at  set of folders  and sub-folders is unchecked, the uncheck will propagate up
 a higher level to become unchecked.  through the hierarchy causing any folders at a higher level to become
   unchecked.
   
   In the case where only a single item may be selected the main subroutine:
   &create_picker() will display the hierarchy of folders and sub-folders for
   only those items for which passback credentials exist,
   
 There is a submit button, which will be named differently according to the   There is a submit button, which will be named differently according to the 
 content in which resource/folder selection is being made.  context in which resource/folder selection is being made.
   
 The two contexts currently supported are: IMS export and selection of  The five contexts currently supported are: IMS export, selection of
 content to be subject to access restructions for the duration of an  content to be subject to access restructions for the duration of an
 exam.    exam, selection of items for dumping to an Authoring Space, display or 
   creation of shortened URLs for deep-linking, and selection of a single
   item for apssback of grades to another CMS.
   
 =head1 INTERNAL SUBROUTINES  =head1 INTERNAL SUBROUTINES
   
 =item &create_picker()  =item &create_picker()
   
 Created HTML mark up to display contents of course with checkboxes to  In the cases where multiple items may be selected ...
   
   Creates HTML markup to display contents of course with checkboxes to
 select items.  Checking a folder causes recursive checking of items  select items.  Checking a folder causes recursive checking of items
 within the folder. Unchecking a resource causing unchecking of folders  within the folder. Unchecking a resource causing unchecking of folders
 containing the item back up to the top level.  containing the item back up to the top level.
   
 Inputs: 7.  In the case where only a single item may be selected ...
   
   Creates HTML markup to display filtered contents of course with radio
   buttons to select an item.
   
   Inputs: 13.
    - $navmap  -- Reference to LON-CAPA navmap object      - $navmap  -- Reference to LON-CAPA navmap object 
                 (encapsulates information about resources in the course).                   (encapsulates information about resources in the course). 
   
    - $context -- Context in which course resource selection is being made.     - $context -- Context in which course resource selection is being made.
                  Currently imsexport and examblock are supported.                   Currently imsexport, examblock, dumpdocs, and shorturls
                    are supported.
   
    - $formname  -- Name of the form in the window from which the pop-up     - $formname  -- Name of the form in the window from which the pop-up
                    used to select course items was launched.                      used to select course items was launched. 
Line 95  Inputs: 7. Line 121  Inputs: 7.
    - $block  -- An internal ID (integer) used to track which exam     - $block  -- An internal ID (integer) used to track which exam
                 block currently being configured.                  block currently being configured.
   
      - $preamble -- HTML form elements used to select Authoring Space
                     if more than one available, and also set name of 'Folder 
                     in Authoring Space' where content will be dumped, when
                     context is 'dumpdocs'.
   
      - $numhome -- number of possible Authoring Spaces where content could
                    be dumped when context is 'dumpdocs'.
   
      - $uploadedfiles -- Reference to hash: keys are paths to files in
                          /home/httpd/lonUsers/$cdom/$1/$2/$3/$cnum/userfiles.
   
      - $tiny -- Reference to hash: keys are symbs of course items for which
                 shortened URLs have already been created.
   
      - $passback -- Reference to hash: keys are symbs of course items for
                     which passback credentials exist. For each symb the
                     hash value is itself a hash of deeplink launch items
                     for that symb with inner hash key set to: 
                     $linkuri\0$linkprotector\0$scope, and corresponding 
                     value of 1.
   
      - $readonly -- if true, no "check all" or "uncheck all" buttons will
                     be displayed, and checkboxes will be disabled, if this 
                     is for an exam block or for shortened URL creation,
                     and radio buttons will be disabled, if this is for
                     passback of scores to another CMS, 
   
   
 Output: $output is the HTML mark-up for display/selection of content  Output: $output is the HTML mark-up for display/selection of content
         items in the pop-up window.          items, either in a pop-up window, or in the main window, 
           depending on context.
   
 =item &respicker_javascript()  =item &respicker_javascript()
   
 Creates javascript functions for checking/unchecking all items, and  Creates javascript functions for checking/unchecking all items, and
 for recursive checking triggered by checking a folder, or recursive  for recursive checking triggered by checking a folder, or recursive
 (upeards) unchecking of an item within a folder.   (upwards) unchecking of an item within a folder. 
   
 Inputs: 7.   Inputs: 9.
    - $startcount -- Starting offset of form element numbering for items       - $startcount -- Starting offset of form element numbering for items  
   
    - $numcount -- Total numer of folders and resources in course.     - $numcount -- Total number of folders and resources in course.
   
    - $context -- Context in which resources are being displayed     - $context -- Context in which resources are being displayed
                  (imsexport or examblock).                    (imsexport, examblock, dumpdocs, shorturls, or
                     crsauthored). 
   
    - $formname --  Name of form.     - $formname --  Name of form.
   
Line 121  Inputs: 7. Line 176  Inputs: 7.
   
    - $checked_maps -- Reference to array of folders currently checked.     - $checked_maps -- Reference to array of folders currently checked.
   
 Output: 1. Javascript (witthin <script></script> tags.     - $numhome -- Number of possible Authoring Spaces on this server 
                    (context is dumpdocs or crsauthored).
    
      - $chkname -- Name of checkboxes used to indicate selection of folder
                    or resource.
   
   Output: 1. Javascript (within <script></script> tags.
   
   
 =item &get_navmap_object()   =item &get_navmap_object() 
Line 132  no object instantiated. Line 193  no object instantiated.
 Inputs: 2.  Inputs: 2.
    - $crstype -- Container type: Course or Community     - $crstype -- Container type: Course or Community
   
    - $context -- Context: imsexport or examblock     - $context -- Context: imsexport, examblock, dumpdocs, shorturls
                             or passback.
   
   
   =item &clean()
    
   Takes incoming title and replaces non-alphanumeric characters with underscore,
   so title can be used as suggested file name (with appended extension) for file
   copied from course to Authoring Space.
   
   
   =item &enumerate_course_contents()
   
   Create hashes of maps (for folders/pages) and symbs (for resources) in
   a course, where keys are numbers (starting with 1) and values are
   map url, or symb, for an iteration through the course, as seen by
   a Course Coordinator. Used to generate numerical IDs to facilitate
   (a) storage of lists of maps or resources to be blocked during an exam,
   (b) processing selected form elements during dumping of selected course
       content to Authoring Space.
   (c) processing of checked checkboxes for creation of shortened URLs for
       deep-linking to course content.
   
   Inputs: 7 
   
         $navmap - navmaps object
   
         $map_url - reference to hash to contain URLs of maps in course
   
         $resource_symb - reference to hash to contain symbs for
                          resources in course
   
         $title_ref - reference to hash containing titles for items in
                      course
   
         $context - examblock, dumpdocs or shorturls
   
         $cdom - course's domain
   
         $cnum - courseID
   
   Outputs: None
   
   Side Effects: $map_url and $resource_symb hashrefs are populated.
   
   
 =over  =over
   
Line 153  use Apache::lonlocal; Line 258  use Apache::lonlocal;
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
   
 sub create_picker {  sub create_picker {
     my ($navmap,$context,$formname,$crstype,$blockedmaps,$blockedresources,$block) = @_;      my ($navmap,$context,$formname,$crstype,$blockedmaps,$blockedresources,$block,$preamble,
           $numhome,$uploadedfiles,$tiny,$passback,$readonly) = @_;
     return unless (ref($navmap));      return unless (ref($navmap));
     my ($it,$output,$numdisc,%maps,%resources,%discussiontime,%currmaps,%currresources);      my ($it,$output,$numdisc,%discussiontime,%currmaps,%currresources,%files,
           %shorturls,%shownmaps,%shownsymbs,%recursed,%retrieved,%pb,$chkname);
       $chkname = 'archive';
       if ($context eq 'shorturls') {
           $chkname = 'addtiny';
       } elsif ($context eq 'passback') {
           $chkname = 'passback';
       }
     $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);      $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
     if (ref($blockedmaps) eq 'HASH') {      if (ref($blockedmaps) eq 'HASH') {
         %currmaps = %{$blockedmaps};          %currmaps = %{$blockedmaps};
     }      }
     if (ref($blockedresources) eq 'HASH') {      if (ref($blockedresources) eq 'HASH') {
         %currresources = %{$blockedresources};          %currresources = %{$blockedresources};
       } elsif (ref($uploadedfiles) eq 'HASH') {
           %files = %{$uploadedfiles};
       } elsif (ref($tiny) eq 'HASH') {
           %shorturls = %{$tiny}; 
       } elsif ($context eq 'passback') {
           if (ref($passback) eq 'HASH') {
               %pb = %{$passback};
               foreach my $symb (keys(%pb)) {
                   my ($map,$id,$url) = &Apache::lonnet::decode_symb($symb);
                   my @recurseup;
                   if ($url =~ /\.(page|sequence)$/) {
                       @recurseup = $navmap->recurseup_maps($url);
                       $shownmaps{&Apache::lonnet::clutter($url)} = 1;
                       if (ref($pb{$symb}) eq 'HASH') {
                           foreach my $entry (keys(%{$pb{$symb}})) {
                               my $scope = (split("\0",$entry))[-1];
                               if (($scope eq 'map') || ($scope eq 'rec')) {
                                   my @contents;
                                   if ($scope eq 'map') {
                                       unless ($retrieved{$url} || $recursed{$url}) {
                                           @contents = $navmap->retrieveResources($url,sub { $_[0]->is_gradable() },0);
                                           $retrieved{$url} = 1;
                                       }
                                   } elsif ($scope eq 'rec') {
                                       unless ($recursed{$url}) {
                                           @contents = $navmap->retrieveResources($url,sub { $_[0]->is_gradable() },1,0,1);
                                           my @subfolders = $navmap->retrieveResources($url,sub { $_[0]->is_map() },1,0,1);
                                           if (@subfolders) {
                                               map { $shownmaps{$_->src()} = 1; } @subfolders;
                                           }
                                           $recursed{$url} = 1;
                                       }
                                   }
                                   if (@contents) {
                                       map { $shownsymbs{$_->symb()} = 1; } @contents;
                                   }
                               }
                           }
                       }
                   } else {
                       @recurseup = $navmap->recurseup_maps($map);
                       $shownmaps{&Apache::lonnet::clutter($map)} = 1;
                       $shownsymbs{$symb} = 1;
                   }
                   if (@recurseup) {
                       map { $shownmaps{&Apache::lonnet::clutter($_)} = 1; } @recurseup;
                   }
               }
           }
     }      }
     my @checked_maps;      my @checked_maps;
     my $curRes;      my $curRes;
Line 174  sub create_picker { Line 336  sub create_picker {
     my %children = ();      my %children = ();
     my %hierarchy = ();      my %hierarchy = ();
     my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons");      my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons");
     my $whitespace =       my $whitespace =
         '<img src="'.$location.'/whitespace_21.gif" class="LC_docs_spacer" alt="" />';          '<img src="'.$location.'/whitespace_21.gif" class="LC_docs_spacer" alt="" />';
   
     my $onsubmit;      my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
       my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
       my $crsprefix = &propath($cdom,$cnum).'/userfiles/';
   
       my ($info,$display,$onsubmit,$togglebuttons,$disabled,$action);
     if ($context eq 'examblock') {      if ($context eq 'examblock') {
         my $maps_elem = 'docs_maps_'.$block;          my $maps_elem = 'docs_maps_'.$block;
         my $res_elem = 'docs_resources_'.$block;          my $res_elem = 'docs_resources_'.$block;
         $onsubmit = ' onsubmit="return writeToOpener('."'$maps_elem','$res_elem'".');"';          $onsubmit = ' onsubmit="return writeToOpener('."'$maps_elem','$res_elem'".');"';
           $info = &mt('Items in '.lc($crstype).' for which access will be blocked.');
           if ($readonly) {
               $disabled = ' disabled="disabled"';
           }
     }      }
     my $display =      if ($context eq 'dumpdocs') {
        '<form name="'.$formname.'" action="" method="post"'.$onsubmit.'>'."\n".          $info = '<span class="LC_fontsize_medium">'.
        '<p>';                  &mt('Choose the uploaded course items and templated pages/problems to be copied to Authoring Space.').
     if ($context eq 'imsexport') {                  '</span><br /><br />';
         $display .= &mt('Choose which items you wish to export from your '.          $startcount = 3 + $numhome;
                         $crstype.'.');          $onsubmit = ' onsubmit="return checkUnique(document.'.$formname.',document.'.$formname.'.'.$chkname.');"';
       } elsif ($context eq 'shorturls') {
           $info = '<span class="LC_fontsize_medium">'.
                   &mt('Choose the resource(s) and/or folder(s) from Main Content for which shortened URL(s) are needed.').
                   '</span><br /><br />';
       } elsif ($context eq 'imsexport') {
           $info = &mt('Choose which items you wish to export from your '.$crstype.'.');
         $startcount = 5;          $startcount = 5;
     } elsif ($context eq 'examblock') {      } elsif ($context eq 'passback') {
         $display .= &mt('Items in '.lc($crstype).' for which access will be blocked.');          $action = '/adm/grades';
           $info = '<p>'.
                   &mt('Select link-protected launch item for which scores should be sent to launcher CMS, then push Next [_1].',
                       '&rarr;').
                   '</p><br />';
           if ($readonly) {
               $disabled = ' disabled="disabled"';
           }
     }      }
     $display .= '</p>';      if ($disabled) {
     if ($context eq 'imsexport') {          $togglebuttons = '<br />';
         $display .= '<div class="LC_columnSection">'."\n".      } elsif ($context ne 'passback') {
                     '<fieldset>'.          $togglebuttons = '<input type="button" value="'.&mt('check all').'" '.
                     '<legend>'.&mt('Content items').'</legend>'."\n";                           'onclick="javascript:checkAll(document.'.$formname.'.'.$chkname.')" />'.
                            '&nbsp;&nbsp;<input type="button" value="'.&mt('uncheck all').'"'.
                            ' onclick="javascript:uncheckAll(document.'.$formname.'.'.$chkname.')" />';
     }      }
     $display .=       $display = '<form name="'.$formname.'" action="'.$action.'" method="post"'.$onsubmit.'>'."\n";
         '<input type="button" value="'.&mt('check all').'" '.  
         'onclick="javascript:checkAll(document.'.$formname.'.archive)" />'.  
         '&nbsp;&nbsp;<input type="button" value="'.&mt('uncheck all').'"'.  
         ' onclick="javascript:uncheckAll(document.'.$formname.'.archive)" />';  
     if ($context eq 'imsexport') {      if ($context eq 'imsexport') {
         $display .= '</fieldset>';          $display .= $info.
         %discussiontime =                      '<div class="LC_columnSection">'."\n".
             &Apache::lonnet::dump('discussiontimes',                      '<fieldset>'.
                                   $env{'course.'.$env{'request.course.id'}.'.domain'},                      '<legend>'.&mt('Content items').'</legend>'."\n".
                                   $env{'course.'.$env{'request.course.id'}.'.num'});                      $togglebuttons.
                       '</fieldset>';
           %discussiontime = &Apache::lonnet::dump('discussiontimes',$cdom,$cnum);
         $numdisc = keys(%discussiontime);          $numdisc = keys(%discussiontime);
         if ($numdisc > 0) {          if ($numdisc > 0) {
             $display .=               $display .= 
Line 221  sub create_picker { Line 404  sub create_picker {
                 ' onclick="javascript:uncheckAll(document.'.$formname.'.discussion)" />'.                  ' onclick="javascript:uncheckAll(document.'.$formname.'.discussion)" />'.
                 '</fieldset>';                  '</fieldset>';
         }          }
         $display .= '</div>';                $display .= '</div>';
       } elsif (($context eq 'examblock') || ($context eq 'shorturls') || ($context eq 'passback')) {
           $display .= $info.$togglebuttons;
       } elsif ($context eq 'dumpdocs') {
           $display .= $preamble.
                       '<div class="LC_left_float">'.
                       '<fieldset>'.
                       '<legend>'.&mt('Content to copy').('&nbsp;'x4).$togglebuttons.'</legend>'.
                       $info;
     }      }
     my $lastcontainer = $startcount;      my $lastcontainer = $startcount;
     $display .= &Apache::loncommon::start_data_table()      $display .= &Apache::loncommon::start_data_table()
Line 233  sub create_picker { Line 424  sub create_picker {
         }          }
     } elsif ($context eq 'examblock') {      } elsif ($context eq 'examblock') {
         $display .= '<th>'.&mt('Access blocked?').'</th>';          $display .= '<th>'.&mt('Access blocked?').'</th>';
       } elsif ($context eq 'dumpdocs') {
           $display .= '<th>'.&mt('Copy?').'</th>'.
                       '<th>'.&mt("Title in $crstype").'</th>'.
                       '<th>'.&mt('Internal Identifier').'</th>'.
                       '<th>'.&mt('Save as ...').'</th>';
       } elsif ($context eq 'shorturls') {
           $display .= '<th colspan="2">'.&mt('Tiny URL').'</th>'.
                       '<th>'.&mt("Title in $crstype").'</th>';
       } elsif ($context eq 'passback') {
           $display .= '<th>'.&mt("Title in $crstype").'</th>'.
                       '<th>'.&mt('Tiny URL Deep-link').'</th>'.
                       '<th>'.&mt('Launcher').'</th>'.
                       '<th  style="padding-left: 6px; padding-right: 6px">'.&mt('Score Type').'</th>'.
                       '<th style="padding-left: 6px; padding-right: 6px">'.&mt('Select').'</th>';
     }      }
     $display .= &Apache::loncommon::end_data_table_header_row();      $display .= &Apache::loncommon::end_data_table_header_row();
     while ($curRes = $it->next()) {      while ($curRes = $it->next()) {
         if (ref($curRes)) {  
              $count ++;  
         }  
         if ($curRes == $it->BEGIN_MAP()) {          if ($curRes == $it->BEGIN_MAP()) {
             $depth++;              $depth++;
             $parent{$depth} = $lastcontainer;              $parent{$depth} = $lastcontainer;
Line 250  sub create_picker { Line 452  sub create_picker {
         if (ref($curRes)) {          if (ref($curRes)) {
             my $symb = $curRes->symb();              my $symb = $curRes->symb();
             my $ressymb = $symb;              my $ressymb = $symb;
             if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {              if ($context eq 'dumpdocs') {
                   next unless (($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(docs|supplemental|simplepage)}) ||
                                ($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(default|supplemental)_\d+\.(sequence|page)}) ||
                                ($curRes->src() eq '/res/lib/templates/simpleproblem.problem') ||
                                ($curRes->src() =~ m{^/adm/$match_domain/$match_username/\d+/smppg}));
               } elsif ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
                 unless ($ressymb =~ m|adm/wrapper/adm|) {                  unless ($ressymb =~ m|adm/wrapper/adm|) {
                     $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';                      $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
                 }                  }
             }              }
             my $currelem = $count+$boards+$startcount;              $count ++;
             $display .= &Apache::loncommon::start_data_table_row().              my ($currelem,$mapurl,$is_map,$showitem);
                        '<td>'."\n".              if ($context eq 'imsexport') {
                        '<input type="checkbox" name="archive" value="'.$count.'" ';                  $currelem = $count+$boards+$startcount;
               } else {
                   $currelem = $count+$startcount;
               }
             if (($curRes->is_sequence()) || ($curRes->is_page())) {              if (($curRes->is_sequence()) || ($curRes->is_page())) {
                 $lastcontainer = $currelem;                  $lastcontainer = $currelem;
                 $display .= 'onclick="javascript:checkFolder(this.form,'."'$currelem'".')" ';                  $mapurl = (&Apache::lonnet::decode_symb($symb))[2];
                 my $mapurl = (&Apache::lonnet::decode_symb($symb))[2];                  $is_map = 1;
                 if ($currmaps{$mapurl}) {              }
                     $display .= 'checked="checked"';              if ($context eq 'passback') {
                     push(@checked_maps,$currelem);                  if (($curRes->is_sequence()) || ($curRes->is_page())) {
                       next unless ($shownmaps{$curRes->src});
                   } else {
                       next unless ($shownsymbs{$symb});
                 }                  }
             } else {              } else {
                 if ($curRes->is_problem()) {                  $display .= &Apache::loncommon::start_data_table_row()."\n";
                     $numprobs ++;              }
               if ($context eq 'shorturls') {
                   if ($shorturls{$symb}) {
                       $display .= '<td>&nbsp;</td><td align="right"><b>'."/tiny/$cdom/$shorturls{$symb}".'</b></td>'."\n";
                   } else {
                       $display .= '<td align="left"><label><input type="checkbox" name="'.$chkname.'" '.
                                   'value="'.$count.'"'.$disabled.' />'.&mt('Add').'</label></td>'.
                                   '<td>&nbsp;</td>'."\n";
                 }                  }
                 $display .= 'onclick="javascript:checkResource(this.form,'."'$currelem'".')" ';              } elsif ($context ne 'passback') {
                 if ($currresources{$symb}) {                  $display .= '<td><input type="checkbox" name="'.$chkname.'" value="'.$count.'" ';
                     $display .= 'checked="checked"';                  if ($is_map) {
                       $display .= 'onclick="javascript:checkFolder(document.'.$formname.','."'$currelem'".')" ';
                       if ($currmaps{$mapurl}) {
                           $display .= 'checked="checked"';
                           push(@checked_maps,$currelem);
                       }
                   } else {
                       if ($curRes->is_problem()) {
                           $numprobs ++;
                       }
                       $display .= 'onclick="javascript:checkResource(document.'.$formname.','."'$currelem'".')" ';
                       if ($currresources{$symb}) {
                           $display .= 'checked="checked"';
                       }
                 }                  }
                   $display .= $disabled.' />'."\n";
               }
               if ($context eq 'dumpdocs') {
                   $display .= '</td><td valign="top">';
               } elsif ($context eq 'shorturls') {
                   $display .= '<td valign="top">';
             }              }
             $display .= ' />'."\n";  
             for (my $i=0; $i<$depth; $i++) {              for (my $i=0; $i<$depth; $i++) {
                 $display .= "$whitespace\n";                  $showitem .= "$whitespace\n";
             }              }
             my $icon = 'src="'.$location.'/unknown.gif" alt=""';              my $icon = 'src="'.$location.'/unknown.gif" alt=""';
             if ($curRes->is_sequence()) {              if ($curRes->is_sequence()) {
Line 292  sub create_picker { Line 530  sub create_picker {
             } elsif ($curRes->src ne '') {              } elsif ($curRes->src ne '') {
                 $icon = 'src="'.&Apache::loncommon::icon($curRes->src).'" alt=""';                  $icon = 'src="'.&Apache::loncommon::icon($curRes->src).'" alt=""';
             }              }
             $display .= '<img '.$icon.' />&nbsp;'."\n";              $showitem .= '<img '.$icon.' />&nbsp;'."\n";
             $children{$parent{$depth}} .= $currelem.':';              $children{$parent{$depth}} .= $currelem.':';
             if ($context eq 'examblock') {              if ($context eq 'examblock') {
                 if ($parent{$depth} > 1) {                  if ($parent{$depth} > 1) {
Line 303  sub create_picker { Line 541  sub create_picker {
                     }                      }
                 }                  }
             }              }
             $display .= '&nbsp;'.$curRes->title().'</td>'."\n";              $showitem .= '&nbsp;'.$curRes->title().$whitespace;
               if ($context eq 'passback') {
                   if ((exists($pb{$symb})) && (ref($pb{$symb}) eq 'HASH')) {
                       my $numlinks = scalar(keys(%{$pb{$symb}}));
                       my $count = 0;
                       foreach my $launcher (sort(keys(%{$pb{$symb}}))) {
                           if ($count == 0) {
                               $display .= &Apache::loncommon::start_data_table_row()."\n";
                               if ($numlinks > 1) {
                                   $display .= '<td rowspan="'.$numlinks.'">'.$showitem.'</td>';
                               } else {
                                   $display .= '<td style="vertical-align: baseline">'.$showitem.'</td>';
                               }
                           } else {
                               $display .= &Apache::loncommon::end_data_table_row().
                                           &Apache::loncommon::start_data_table_row()."\n";
                           }
                           my ($linkuri,$linkprotector,$scope) = split("\0",$launcher);
                           my ($ltinum,$ltitype) = ($linkprotector =~ /^(\d+)(c|d)$/);
                           my ($appname,$setter);
                           if ($ltitype eq 'c') {
                               my %lti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider');
                               if (ref($lti{$ltinum}) eq 'HASH') {
                                   $appname = $lti{$ltinum}{'name'};
                                   if ($appname) {
                                       $setter = ' (defined in course)';
                                   }
                               }
                           } elsif ($ltitype eq 'd') {
                               my %lti = &Apache::lonnet::get_domain_lti($cdom,'linkprot');
                               if (ref($lti{$ltinum}) eq 'HASH') {
                                   $appname = $lti{$ltinum}{'name'};
                                   if ($appname) {
                                       $setter = ' (defined in domain)';
                                   }
                               }
                           }
                           my $shownscope;
                           if ($scope eq 'res') {
                               $shownscope = &mt('Resource');
                           } elsif ($scope eq 'map') {
                               $shownscope = &mt('Folder');
                           }  elsif ($scope eq 'rec') {
                               $shownscope = &mt('Folder + sub-folders');
                           }
                           $display .= '<td style="vertical-align: baseline"><span style="font-weight: bold;">'.$linkuri.'</span></td>'."\n".
                                       '<td style="vertical-align: baseline; padding-left: 6px; padding-right: 6px">'.$appname.$setter.'</td>'."\n".
                                       '<td style="vertical-align: baseline"><span style="font-style: italic;">'.$shownscope.'</span></td>'."\n".
                                       '<td align="right" style="vertical-align: baseline"><input type="radio" name="'.$chkname.'" '.
                                       'value="'.&escape($launcher).'"'.$disabled.' /></td>'."\n";
                           $count ++;
                       }
                   } else {
                       $display .= &Apache::loncommon::start_data_table_row()."\n".
                                   '<td colspan="5">'.$showitem.'</td>';
                   }
               } else {
                   $display .= $showitem.'</td>'."\n";
               }
             if ($context eq 'imsexport') {              if ($context eq 'imsexport') {
 # Existing discussion posts?  # Existing discussion posts?
                 if ($discussiontime{$ressymb} > 0) {                  if ($discussiontime{$ressymb} > 0) {
Line 315  sub create_picker { Line 610  sub create_picker {
                 } elsif ($numdisc > 0) {                  } elsif ($numdisc > 0) {
                     $display .= '<td>&nbsp;</td>'."\n";                      $display .= '<td>&nbsp;</td>'."\n";
                 }                  }
               } elsif ($context eq 'dumpdocs') {
                   my $src = $curRes->src();
                   my ($filepath,$title);
                   if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E}) {
                       $filepath = &Apache::lonnet::filelocation('',$src);
                       $filepath =~ s/\Q$crsprefix\E//;
                       if ($curRes->is_map()) {
                           $title = $files{$filepath};
                       } else {
                           $filepath =~ s{docs/}{}; 
                           $title = $filepath;
                           $title =~ s{^(default|\d+)/\d*/?}{};
                       }
                   } else {
                       $title = $curRes->title();
                       $title =~ s{/}{_}g;
                       $title = &clean($title);
                       if ($src eq '/res/lib/templates/simpleproblem.problem') {
                           my ($map,$id,$res) = &Apache::lonnet::decode_symb($symb);
                           $map =~ s{^uploaded/$cdom/$cnum/}{};
                           $filepath = $map.'_'.$id;
                           $title .= '.problem';
                       } elsif ($src =~ m{^/adm/$match_domain/$match_username/(\d+)/smppg}) {
                           $filepath = 'smppage_'.$1.'.db';
                           $title .= '.html';
                       }
                   }
                   $display .= '<td>'.$filepath.'</td>'.
                               '<td><input type="text" size="40" name="namefor_'.$count.'" id="namefor_'.$count.'" value="'.$title.'" /></td>'."\n";
             }              }
             $display .= &Apache::loncommon::end_data_table_row();              $display .= &Apache::loncommon::end_data_table_row();
         }          }
Line 332  sub create_picker { Line 656  sub create_picker {
                         '&nbsp;'.&mt('Text').'</label></span></p>';                          '&nbsp;'.&mt('Text').'</label></span></p>';
         }          }
     }      }
     $display .= '<p>';      my $numcount;
     if ($context eq 'imsexport') {      if ($context eq 'imsexport') {
         $display .=           $display .= 
              '<p>'.
            '<input type="hidden" name="finishexport" value="1" />'.             '<input type="hidden" name="finishexport" value="1" />'.
            '<input type="submit" name="exportcourse" value="'.             '<input type="submit" name="exportcourse" value="'.
            &mt('Export').'" />';             &mt('Export').'" /></p>';
           $numcount = $count + $boards + $startcount;
     } elsif ($context eq 'examblock') {      } elsif ($context eq 'examblock') {
         $display .=          unless ($readonly) {
             '<input type="submit" name="resourceblocks" value="'.              $display .=
             &mt('Copy Choices to Main Window').'" />';                  '<p>'.
     }                  '<input type="submit" name="resourceblocks" value="'.
     $display .= '</p></form>';                  &mt('Copy Choices to Main Window').'" /></p>';
     my $numcount = $count + $boards + $startcount;          }
     my $scripttag =           $numcount = $count + $startcount;
       } elsif ($context eq 'dumpdocs') {
           $display .= '</fieldset>'.
                       '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'.
                       '<div>'.
                       '<input type="submit" name="dumpcourse" value="'.&mt("Copy $crstype Content").'" />'.
                       '</div>';
           $numcount = $count + $startcount;
       } elsif ($context eq 'shorturls') {
           unless ($readonly) {
               $display .=
                   '<p>'.
                   '<input type="submit" name="shorturls" value="'.
                   &mt('Create Tiny URL(s)').'" /></p>';
           }
       } elsif ($context eq 'passback') {
           unless ($readonly) {
               $display .=
                   '<p>'.
                   '<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($env{'form.symb'}).'" />'."\n".
                   '<input type="hidden" name="command" value="passback" />'.
                   '<input type="submit" name="picklauncher" value="'.
                   &mt('Next').' &rarr;" /></p>';
           }
       }
       $display .= '</form>';
       if ($context eq 'passback') {
           return $display;
       }
       my $scripttag =
         &respicker_javascript($startcount,$numcount,$context,$formname,\%children,          &respicker_javascript($startcount,$numcount,$context,$formname,\%children,
                               \%hierarchy,\@checked_maps);                                \%hierarchy,\@checked_maps,$numhome,$chkname);
       if (($context eq 'dumpdocs') || ($context eq 'shorturls')) {
           return $scripttag.$display; 
       }
     my ($title,$crumbs,$args);      my ($title,$crumbs,$args);
     if ($context eq 'imsexport') {      if ($context eq 'imsexport') { 
         $title = 'Export '.$crstype.' to IMS Package';          $title = 'Export '.$crstype.' to IMS Package';
     } elsif ($context eq 'examblock') {      } elsif ($context eq 'examblock') {
         $title = 'Resources with Access blocked';          $title = 'Resources with Access blocked';
Line 361  sub create_picker { Line 719  sub create_picker {
     if ($context eq 'imsexport') {      if ($context eq 'imsexport') {
         $output .= &Apache::lonhtmlcommon::breadcrumbs('IMS Export').          $output .= &Apache::lonhtmlcommon::breadcrumbs('IMS Export').
                    &Apache::londocs::startContentScreen('tools');                     &Apache::londocs::startContentScreen('tools');
       } elsif ($context eq 'dumpdocs') {
           $output .= &Apache::lonhtmlcommon::breadcrumbs('Copying to Authoring Space').
                      &Apache::londocs::startContentScreen('tools');
     }      }
     $output .= $display;      $output .= $display;
     if ($context eq 'examblock') {      if ($context eq 'examblock') {
Line 373  sub create_picker { Line 734  sub create_picker {
   
 sub respicker_javascript {  sub respicker_javascript {
     my ($startcount,$numitems,$context,$formname,$children,$hierarchy,      my ($startcount,$numitems,$context,$formname,$children,$hierarchy,
         $checked_maps) = @_;          $checked_maps,$numhome,$chkname) = @_;
     return unless ((ref($children) eq 'HASH') && (ref($hierarchy) eq 'HASH')      my $check_uncheck = <<"FIRST";
                    && (ref($checked_maps) eq 'ARRAY'));  
     my $scripttag = <<"START";  
 <script type="text/javascript">  
 // <![CDATA[  
 function checkAll(field) {  function checkAll(field) {
     if (field.length > 0) {      if (field.length > 0) {
         for (i = 0; i < field.length; i++) {          for (i = 0; i < field.length; i++) {
Line 398  function uncheckAll(field) { Line 755  function uncheckAll(field) {
         field.checked = false;          field.checked = false;
     }      }
 }  }
   FIRST
       if ($context eq 'shorturls') {
           return <<"END";
   <script type="text/javascript">
   // <![CDATA[
   $check_uncheck
   // ]]>
   </script>
   END
       }
       return unless ((ref($children) eq 'HASH') && (ref($hierarchy) eq 'HASH')
                      && (ref($checked_maps) eq 'ARRAY'));
       my ($elem,$nested,$nameforelem);
       if ($context eq 'dumpdocs') {
           $elem='((parseInt(item)-'.$startcount.')*2)+'.$startcount;
           $nested='((parseInt(nesting[item][i])-'.$startcount.')*2)+'.$startcount;
           $nameforelem=$elem+1;
       } else {
           $elem='parseInt(item)';
           $nested='parseInt(nesting[item][i])';
       }
       my $scripttag = <<"START";
   <script type="text/javascript">
   // <![CDATA[
   $check_uncheck
   
 function checkFolder(form,item) {  function checkFolder(form,item) {
     if (form.elements[item].checked == true) {      var elem = $elem;
       if (form.elements[elem].checked == true) {
         containerCheck(form,item);          containerCheck(form,item);
     } else {      } else {
         containerUncheck(form,item);          containerUncheck(form,item);
Line 408  function checkFolder(form,item) { Line 791  function checkFolder(form,item) {
 }  }
   
 function checkResource(form,item) {  function checkResource(form,item) {
     if (form.elements[item].checked == false) {      var elem = $elem;
       if (form.elements[elem].checked == false) {
         containerUncheck(form,item);          containerUncheck(form,item);
     }      }
 }  }
   
 numitems = $numitems;  numitems = $startcount + $numitems;
 var parents = new Array(numitems);  var parents = new Array(numitems);
 var nesting = new Array(numitems);  var nesting = new Array(numitems);
 var initial = new Array();  var initial = new Array();
Line 452  function recurseFolders() { Line 836  function recurseFolders() {
 }  }
   
 EXTRA  EXTRA
       } elsif ($context eq 'dumpdocs') {
           my $blankmsg = &mt('An item selected has no filename set in the "Save as ..." column.');
           my $dupmsg = &mt('Items selected for copying need unique filenames in the "Save as ..." column.');
           my $homemsg = &mt('An Authoring Space needs to be selected.');
           &js_escape(\$blankmsg);
           &js_escape(\$dupmsg);
           &js_escape(\$homemsg);
           $scripttag .= <<"EXTRA";
   
   function checkUnique(form,field) {
       var duplicate = 0;
       var blank = 0;
       var numhome = '$numhome';
       if (field.length > 0) {
           for (i=0; i<field.length; i++) {
               if (field[i].checked) {
                   var item = field[i].value;
                   var namefor = document.getElementById('namefor_'+item);
                   if (namefor) {
                       var possval = namefor.value;
                       if (!possval) {
                           blank = item;
                           break;
                       }
                       for (j=i+1; j<field.length; j++) {
                           if (field[j].checked) {
                               var curritem = field[j].value;
                               var currnamefor = document.getElementById('namefor_'+curritem);
                               if (currnamefor) {
                                   var currval = currnamefor.value;
                                   if (currval == possval) {
                                       duplicate = curritem;
                                       break;
                                   }
                               }
                           }
                       }
                       if (duplicate) {
                           break;
                       }
                   }
               }
           }
       }
       if (blank) {
           alert('$blankmsg');
           return false;
       }
       if (duplicate) {
           alert('$dupmsg');
           return false;
       }
       if (numhome > 1) {
           if (!form.authorspace.options[form.authorspace.selectedIndex].value) {
               alert('$homemsg');
               return false;
           }
       }
       return true;
   }
   
   EXTRA
   
     }      }
   
     $scripttag .= <<"END";      $scripttag .= <<"END";
   
 function containerCheck(form,item) {  function containerCheck(form,item) {
     form.elements[item].checked = true;      var elem = $elem;
       form.elements[elem].checked = true;
     if(Object.prototype.toString.call(parents[item]) === '[object Array]') {      if(Object.prototype.toString.call(parents[item]) === '[object Array]') {
         if (parents[item].length > 0) {          if (parents[item].length > 0) {
             for (var j=0; j<parents[item].length; j++) {              for (var j=0; j<parents[item].length; j++) {
Line 471  function containerUncheck(form,item) { Line 919  function containerUncheck(form,item) {
     if(Object.prototype.toString.call(nesting[item]) === '[object Array]') {      if(Object.prototype.toString.call(nesting[item]) === '[object Array]') {
         if (nesting[item].length > 0) {          if (nesting[item].length > 0) {
             for (var i=0; i<nesting[item].length; i++) {              for (var i=0; i<nesting[item].length; i++) {
                 form.elements[nesting[item][i]].checked = false;                  var nested = $nested;
             }              }
         }          }
     }      }
Line 485  END Line 933  END
 function writeToOpener(maps,resources) {  function writeToOpener(maps,resources) {
     var checkedmaps = '';      var checkedmaps = '';
     var checkedresources = '';      var checkedresources = '';
     for (var i=0; i<document.$formname.archive.length; i++) {      for (var i=0; i<document.$formname.${chkname}.length; i++) {
         if (document.$formname.archive[i].checked) {          if (document.$formname.${chkname}[i].checked) {
             var isResource = 1;              var isResource = 1;
             var include = 1;              var include = 1;
             var elemnum = i+1+$startcount;              var elemnum = i+1+$startcount;
Line 496  function writeToOpener(maps,resources) { Line 944  function writeToOpener(maps,resources) {
                 }                  }
             }              }
             if (isResource == 1) {              if (isResource == 1) {
                 if (nesting[elemnum].length > 0) {                  if (nesting[elemnum] != null) {
                     var lastelem = nesting[elemnum].length-1;                      if (nesting[elemnum].length > 0) {
                     if (document.$formname.elements[nesting[elemnum][lastelem]].checked) {                          var lastelem = nesting[elemnum].length-1;
                         include = 0;                          if (document.$formname.elements[nesting[elemnum][lastelem]].checked) {
                               include = 0;
                           }
                     }                      }
                 }                  }
             }              }
             if (include == 1) {              if (include == 1) {
                 if (isResource == 1) {                  if (isResource == 1) {
                     checkedresources += document.$formname.archive[i].value+',';                      checkedresources += document.$formname.${chkname}[i].value+',';
                 } else {                  } else {
                     checkedmaps += document.$formname.archive[i].value+',';                      checkedmaps += document.$formname.${chkname}[i].value+',';
                 }                  }
             }              }
         }          }
Line 540  sub get_navmap_object { Line 990  sub get_navmap_object {
             $outcome = &Apache::loncommon::start_page('Selection of Resources for Blocking',              $outcome = &Apache::loncommon::start_page('Selection of Resources for Blocking',
                                                        undef,{'only_body' => 1,}).                                                         undef,{'only_body' => 1,}).
                       '<h2>'.&mt('Resource Display Failed').'</h2>';                          '<h2>'.&mt('Resource Display Failed').'</h2>';  
         }           } elsif ($context eq 'dumpdocs') {
               $outcome = '<h2>'.&mt('Copying to Authoring Space unavailable').'</h2>';
           } elsif ($context eq 'shorturls') {
               $outcome = '<h2>'.&mt('Display/Setting of shortened URLs unavailable').'</h2>';
           }
         $outcome .= '<div class="LC_error">';          $outcome .= '<div class="LC_error">';
         if ($crstype eq 'Community') {          if ($crstype eq 'Community') {
             $outcome .= &mt('Unable to retrieve information about community contents');              $outcome .= &mt('Unable to retrieve information about community contents');
Line 548  sub get_navmap_object { Line 1002  sub get_navmap_object {
             $outcome .= &mt('Unable to retrieve information about course contents');              $outcome .= &mt('Unable to retrieve information about course contents');
         }          }
         $outcome .= '</div>';          $outcome .= '</div>';
         if ($context eq 'imsexport') {          if (($context eq 'imsexport') || ($context eq 'dumpdocs') || ($context eq 'shorturls') ) {
             $outcome .= '<a href="/adm/coursedocs">';              $outcome .= '<a href="/adm/coursedocs">';
             if ($crstype eq 'Community') {              if ($crstype eq 'Community') {
                 $outcome .= &mt('Return to Community Editor');                  $outcome .= &mt('Return to Community Editor');
Line 556  sub get_navmap_object { Line 1010  sub get_navmap_object {
                 $outcome .= &mt('Return to Course Editor');                  $outcome .= &mt('Return to Course Editor');
             }              }
             $outcome .= '</a>';              $outcome .= '</a>';
             &logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});              if ($context eq 'imsexport') {
                   &Apache::lonnet::logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
               } elsif ($context eq 'dumpdocs') {
                   &Apache::lonnet::logthis('Copying to Authoring Space failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
               } elsif ($context eq 'shorturls') {
                   &Apache::lonnet::logthis('Displaying and/or saving URL shortcuts failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
               }
         } elsif ($context eq 'examblock') {          } elsif ($context eq 'examblock') {
             $outcome .=  '<href="javascript:window.close();">'.&mt('Close window').'</a>';                       $outcome .=  '<href="javascript:window.close();">'.&mt('Close window').'</a>';         
         }          }
Line 566  sub get_navmap_object { Line 1026  sub get_navmap_object {
     }      }
 }  }
   
   sub clean {
       my ($title)=@_;
       $title=~s/[^\w\/\!\$\%\^\*\-\_\=\+\;\:\,\\\|\`\~]+/\_/gs;
       return $title;
   }
   
   sub enumerate_course_contents {
       my ($navmap,$map_url,$resource_symb,$titleref,$context,$cdom,$cnum) = @_;
       if ((ref($navmap)) && (ref($map_url) eq 'HASH') &&
           (ref($resource_symb) eq 'HASH') && (ref($titleref) eq 'HASH')) {
           my $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
           my $count = 0;
           while (my $curRes = $it->next()) {
               if (ref($curRes)) {
                   my $symb = $curRes->symb();
                   my $ressymb = $symb;
                   if ($context eq 'dumpdocs') {
                       next unless (($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(docs|supplemental|simplepage)/}) ||
                                    ($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(default|supplemental)_\d+\.(sequence|page)}) ||
                                    ($curRes->src() eq '/res/lib/templates/simpleproblem.problem') ||
                                    ($curRes->src() =~ m{^/adm/$match_domain/$match_username/\d+/smppg}));
                   } elsif ($ressymb =~ m{adm/($match_domain)/($match_username)/(\d+)/bulletinboard$}) {
                       unless ($ressymb =~ m{adm/wrapper/adm}) {
                           $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.
                                      '/bulletinboard';
                       }
                   }
                   $count ++;
                   if ($context eq 'shorturls') {
                       $resource_symb->{$count} = $ressymb;
                   } else {
                       if (($curRes->is_sequence()) || ($curRes->is_page())) {
                           $map_url->{$count} = (&Apache::lonnet::decode_symb($symb))[2];
                       } else {
                           $resource_symb->{$count} = $ressymb;
                       }
                   }
                   $titleref->{$count} = $curRes->title();
               }
           }
       }
       return;
   }
   
 1;  1;

Removed from v.1.4  
changed lines
  Added in v.1.21


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