Annotation of loncom/interface/loncourserespicker.pm, revision 1.19

1.1       raeburn     1: # The LearningOnline Network
                      2: #
1.19    ! raeburn     3: # $Id: loncourserespicker.pm,v 1.18 2024/11/24 04:17:50 raeburn Exp $
1.1       raeburn     4: #
                      5: # Copyright Michigan State University Board of Trustees
                      6: #
                      7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      8: #
                      9: # LON-CAPA is free software; you can redistribute it and/or modify
                     10: # it under the terms of the GNU General Public License as published by
                     11: # the Free Software Foundation; either version 2 of the License, or
                     12: # (at your option) any later version.
                     13: #
                     14: # LON-CAPA is distributed in the hope that it will be useful,
                     15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     17: # GNU General Public License for more details.
                     18: #
                     19: # You should have received a copy of the GNU General Public License
                     20: # along with LON-CAPA; if not, write to the Free Software
                     21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     22: #
                     23: # /home/httpd/html/adm/gpl.txt
                     24: #
                     25: # http://www.lon-capa.org/
                     26: #
                     27: 
                     28: =pod
                     29: 
                     30: =head1 NAME
                     31: 
                     32: loncourserespicker - Utilities to choose folders and resources in a course.
                     33: 
                     34: =head1 SYNOPSIS
                     35: 
1.19    ! raeburn    36: loncourserespicker provides either (1) an interface for selecting which 
        !            37: folders and/or resources are to be selected for a specific action, one of: 
1.1       raeburn    38: 
1.19    ! raeburn    39: (a) export to an IMS Content Package
        !            40: (b) be subject to access blocking for the duration of an exam/quiz.
        !            41: (c) dump to an Authoring Space
1.15      raeburn    42: (d) receive shortened URLs to be used when deep-linking into a course
1.1       raeburn    43: 
1.19    ! raeburn    44: or (2) an interface for selecting a single folder or resource for which 
        !            45: existing passback credentials can be used to send scores to another Course
        !            46: Management System (CMS).
        !            47: 
1.1       raeburn    48: =head1 DESCRIPTION
                     49: 
                     50: This module provides routines to generate a hierarchical display of folders
1.19    ! raeburn    51: and resources in a course which can be selected for specific actions. In 
        !            52: all except one use case all items in the course are shown. The case where
        !            53: only a filtered list is shown is passback of scores, and filtering limits
        !            54: folders and resources to those items for which passback credentials exist,
        !            55: (and their parent folders).
        !            56: 
        !            57: When the display is shown in a pop-up window, The choice of items will be
        !            58: copied back to the main window from which the pop-up window used to display
        !            59: the Course Contents was opened.
1.1       raeburn    60: 
                     61: =head1 OVERVIEW
                     62: 
1.19    ! raeburn    63: In the cases where multiple items may be selected the main subroutine:
        !            64: &create_picker() will display the hierarchy of folders, sub-folders, and
        !            65: resources in the Main Content area. Items can be selected using checkboxes,
        !            66: and/or a "Check All" button.  Selection of a folder causes the contents of
        !            67: the folder to also be selected automatically. The propagation of check
        !            68: status is recursive into sub-folders.  Likewise, if an item deep in a nested
        !            69: set of folders  and sub-folders is unchecked, the uncheck will propagate up
        !            70: through the hierarchy causing any folders at a higher level to become
        !            71: unchecked.
        !            72: 
        !            73: In the case where only a single item may be selected the main subroutine:
        !            74: &create_picker() will display the hierarchy of folders and sub-folders for
        !            75: only those items for which passback credentials exist,
1.1       raeburn    76: 
                     77: There is a submit button, which will be named differently according to the 
1.7       raeburn    78: context in which resource/folder selection is being made.
1.1       raeburn    79: 
1.19    ! raeburn    80: The five contexts currently supported are: IMS export, selection of
1.1       raeburn    81: content to be subject to access restructions for the duration of an
1.19    ! raeburn    82: exam, selection of items for dumping to an Authoring Space, display or 
        !            83: creation of shortened URLs for deep-linking, and selection of a single
        !            84: item for apssback of grades to another CMS.
1.1       raeburn    85: 
                     86: =head1 INTERNAL SUBROUTINES
                     87: 
                     88: =item &create_picker()
                     89: 
1.19    ! raeburn    90: In the cases where multiple items may be selected ...
        !            91: 
        !            92: Creates HTML markup to display contents of course with checkboxes to
1.1       raeburn    93: select items.  Checking a folder causes recursive checking of items
                     94: within the folder. Unchecking a resource causing unchecking of folders
                     95: containing the item back up to the top level.
                     96: 
1.19    ! raeburn    97: In the case where only a single item may be selected ...
        !            98: 
        !            99: Creates HTML markup to display filtered contents of course with radio
        !           100: buttons to select an item.
        !           101: 
        !           102: Inputs: 13.
1.1       raeburn   103:    - $navmap  -- Reference to LON-CAPA navmap object 
                    104:                 (encapsulates information about resources in the course). 
                    105: 
                    106:    - $context -- Context in which course resource selection is being made.
1.15      raeburn   107:                  Currently imsexport, examblock, dumpdocs, and shorturls
                    108:                  are supported.
1.1       raeburn   109: 
                    110:    - $formname  -- Name of the form in the window from which the pop-up
                    111:                    used to select course items was launched. 
                    112: 
                    113:    - $crstype  -- Course or Community
                    114: 
                    115:    - $blockedmaps -- Reference to hash of previously selected maps
                    116:                      (e.g., for a live exam block).   
                    117: 
                    118:    - $blockedresources  -- Reference to hash of resources selected
                    119:                            previously (e.g., for an exam block).  
                    120: 
                    121:    - $block  -- An internal ID (integer) used to track which exam
                    122:                 block currently being configured.
                    123: 
1.7       raeburn   124:    - $preamble -- HTML form elements used to select Authoring Space
                    125:                   if more than one available, and also set name of 'Folder 
                    126:                   in Authoring Space' where content will be dumped, when
                    127:                   context is 'dumpdocs'.
                    128: 
                    129:    - $numhome -- number of possible Authoring Spaces where content could
                    130:                  be dumped when context is 'dumpdocs'.
                    131: 
                    132:    - $uploadedfiles -- Reference to hash: keys are paths to files in
                    133:                        /home/httpd/lonUsers/$cdom/$1/$2/$3/$cnum/userfiles.
1.15      raeburn   134: 
                    135:    - $tiny -- Reference to hash: keys are symbs of course items for which
                    136:               shortened URLs have already been created.
                    137: 
1.19    ! raeburn   138:    - $passback -- Reference to hash: keys are symbs of course items for
        !           139:                   which passback credentials exist. For each symb the
        !           140:                   hash value is itself a hash of deeplink launch items
        !           141:                   for that symb with inner hash key set to: 
        !           142:                   $linkuri\0$linkprotector\0$scope, and corresponding 
        !           143:                   value of 1.
        !           144: 
1.14      raeburn   145:    - $readonly -- if true, no "check all" or "uncheck all" buttons will
                    146:                   be displayed, and checkboxes will be disabled, if this 
1.19    ! raeburn   147:                   is for an exam block or for shortened URL creation,
        !           148:                   and radio buttons will be disabled, if this is for
        !           149:                   passback of scores to another CMS, 
1.7       raeburn   150: 
1.1       raeburn   151: 
                    152: Output: $output is the HTML mark-up for display/selection of content
1.19    ! raeburn   153:         items, either in a pop-up window, or in the main window, 
        !           154:         depending on context.
1.1       raeburn   155: 
                    156: =item &respicker_javascript()
                    157: 
                    158: Creates javascript functions for checking/unchecking all items, and
                    159: for recursive checking triggered by checking a folder, or recursive
                    160: (upeards) unchecking of an item within a folder. 
                    161: 
                    162: Inputs: 7. 
                    163:    - $startcount -- Starting offset of form element numbering for items  
                    164: 
                    165:    - $numcount -- Total numer of folders and resources in course.
                    166: 
                    167:    - $context -- Context in which resources are being displayed
1.17      raeburn   168:                  (imsexport, examblock,  dumpdocs or shorturls). 
1.1       raeburn   169: 
                    170:    - $formname --  Name of form.
                    171: 
                    172:    - $children -- Reference to hash of items contained within a folder. 
                    173: 
                    174:    - $hierarchy -- Reference to hierarchy of folders containing an item.
                    175: 
                    176:    - $checked_maps -- Reference to array of folders currently checked.
                    177: 
1.7       raeburn   178: Output: 1. Javascript (within <script></script> tags.
1.1       raeburn   179: 
                    180: 
                    181: =item &get_navmap_object() 
                    182: 
                    183: Instantiates a navmaps object, and generates an error message if
                    184: no object instantiated.
                    185: 
                    186: Inputs: 2.
                    187:    - $crstype -- Container type: Course or Community
                    188: 
1.19    ! raeburn   189:    - $context -- Context: imsexport, examblock, dumpdocs, shorturls
        !           190:                           or passback.
1.7       raeburn   191: 
                    192: 
                    193: =item &clean()
                    194:  
                    195: Takes incoming title and replaces non-alphanumeric characters with underscore,
                    196: so title can be used as suggested file name (with appended extension) for file
1.11      bisitz    197: copied from course to Authoring Space.
1.7       raeburn   198: 
                    199: 
                    200: =item &enumerate_course_contents()
                    201: 
                    202: Create hashes of maps (for folders/pages) and symbs (for resources) in
                    203: a course, where keys are numbers (starting with 1) and values are
                    204: map url, or symb, for an iteration through the course, as seen by
                    205: a Course Coordinator. Used to generate numerical IDs to facilitate
                    206: (a) storage of lists of maps or resources to be blocked during an exam,
1.18      raeburn   207: (b) processing selected form elements during dumping of selected course
1.11      bisitz    208:     content to Authoring Space.
1.18      raeburn   209: (c) processing of checked checkboxes for creation of shortened URLs for
                    210:     deep-linking to course content.
1.7       raeburn   211: 
                    212: Inputs: 7 
                    213: 
                    214:       $navmap - navmaps object
                    215: 
                    216:       $map_url - reference to hash to contain URLs of maps in course
                    217: 
                    218:       $resource_symb - reference to hash to contain symbs for
                    219:                        resources in course
                    220: 
                    221:       $title_ref - reference to hash containing titles for items in
                    222:                    course
                    223: 
1.17      raeburn   224:       $context - examblock, dumpdocs or shorturls
1.7       raeburn   225: 
                    226:       $cdom - course's domain
                    227: 
1.18      raeburn   228:       $cnum - courseID
1.7       raeburn   229: 
                    230: Outputs: None
                    231: 
                    232: Side Effects: $map_url and $resource_symb hashrefs are populated.
                    233: 
1.1       raeburn   234: 
                    235: =over
                    236: 
                    237: =back
                    238: 
                    239: =cut
                    240: 
                    241: 
                    242: package Apache::loncourserespicker;
                    243: 
                    244: use strict;
                    245: use Apache::lonnet;
                    246: use Apache::loncommon;
                    247: use Apache::lonhtmlcommon;
                    248: use Apache::lonnavmaps;
1.2       raeburn   249: use Apache::londocs;
1.1       raeburn   250: use Apache::lonlocal;
                    251: use LONCAPA qw(:DEFAULT :match);
                    252: 
                    253: sub create_picker {
1.14      raeburn   254:     my ($navmap,$context,$formname,$crstype,$blockedmaps,$blockedresources,$block,$preamble,
1.19    ! raeburn   255:         $numhome,$uploadedfiles,$tiny,$passback,$readonly) = @_;
1.1       raeburn   256:     return unless (ref($navmap));
1.16      raeburn   257:     my ($it,$output,$numdisc,%discussiontime,%currmaps,%currresources,%files,
1.19    ! raeburn   258:         %shorturls,%shownmaps,%shownsymbs,%recursed,%retrieved,%pb,$chkname);
1.15      raeburn   259:     $chkname = 'archive';
                    260:     if ($context eq 'shorturls') {
                    261:         $chkname = 'addtiny';
1.19    ! raeburn   262:     } elsif ($context eq 'passback') {
        !           263:         $chkname = 'passback';
1.15      raeburn   264:     }
1.1       raeburn   265:     $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
                    266:     if (ref($blockedmaps) eq 'HASH') {
                    267:         %currmaps = %{$blockedmaps};
                    268:     }
                    269:     if (ref($blockedresources) eq 'HASH') {
                    270:         %currresources = %{$blockedresources};
1.7       raeburn   271:     } elsif (ref($uploadedfiles) eq 'HASH') {
                    272:         %files = %{$uploadedfiles};
1.15      raeburn   273:     } elsif (ref($tiny) eq 'HASH') {
                    274:         %shorturls = %{$tiny}; 
1.19    ! raeburn   275:     } elsif ($context eq 'passback') {
        !           276:         if (ref($passback) eq 'HASH') {
        !           277:             %pb = %{$passback};
        !           278:             foreach my $symb (keys(%pb)) {
        !           279:                 my ($map,$id,$url) = &Apache::lonnet::decode_symb($symb);
        !           280:                 my @recurseup;
        !           281:                 if ($url =~ /\.(page|sequence)$/) {
        !           282:                     @recurseup = $navmap->recurseup_maps($url);
        !           283:                     $shownmaps{&Apache::lonnet::clutter($url)} = 1;
        !           284:                     if (ref($pb{$symb}) eq 'HASH') {
        !           285:                         foreach my $entry (keys(%{$pb{$symb}})) {
        !           286:                             my $scope = (split("\0",$entry))[-1];
        !           287:                             if (($scope eq 'map') || ($scope eq 'rec')) {
        !           288:                                 my @contents;
        !           289:                                 if ($scope eq 'map') {
        !           290:                                     unless ($retrieved{$url} || $recursed{$url}) {
        !           291:                                         @contents = $navmap->retrieveResources($url,sub { $_[0]->is_gradable() },0);
        !           292:                                         $retrieved{$url} = 1;
        !           293:                                     }
        !           294:                                 } elsif ($scope eq 'rec') {
        !           295:                                     unless ($recursed{$url}) {
        !           296:                                         @contents = $navmap->retrieveResources($url,sub { $_[0]->is_gradable() },1,0,1);
        !           297:                                         my @subfolders = $navmap->retrieveResources($url,sub { $_[0]->is_map() },1,0,1);
        !           298:                                         if (@subfolders) {
        !           299:                                             map { $shownmaps{$_->src()} = 1; } @subfolders;
        !           300:                                         }
        !           301:                                         $recursed{$url} = 1;
        !           302:                                     }
        !           303:                                 }
        !           304:                                 if (@contents) {
        !           305:                                     map { $shownsymbs{$_->symb()} = 1; } @contents;
        !           306:                                 }
        !           307:                             }
        !           308:                         }
        !           309:                     }
        !           310:                 } else {
        !           311:                     @recurseup = $navmap->recurseup_maps($map);
        !           312:                     $shownmaps{&Apache::lonnet::clutter($map)} = 1;
        !           313:                     $shownsymbs{$symb} = 1;
        !           314:                 }
        !           315:                 if (@recurseup) {
        !           316:                     map { $shownmaps{&Apache::lonnet::clutter($_)} = 1; } @recurseup;
        !           317:                 }
        !           318:             }
        !           319:         }
1.1       raeburn   320:     }
                    321:     my @checked_maps;
                    322:     my $curRes;
                    323:     my $numprobs = 0;
                    324:     my $depth = 0;
                    325:     my $count = 0;
                    326:     my $boards = 0;
                    327:     my $startcount = 1;
                    328:     my %parent = ();
                    329:     my %children = ();
                    330:     my %hierarchy = ();
                    331:     my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons");
1.7       raeburn   332:     my $whitespace =
1.1       raeburn   333:         '<img src="'.$location.'/whitespace_21.gif" class="LC_docs_spacer" alt="" />';
                    334: 
1.7       raeburn   335:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
                    336:     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
                    337:     my $crsprefix = &propath($cdom,$cnum).'/userfiles/';
                    338: 
1.19    ! raeburn   339:     my ($info,$display,$onsubmit,$togglebuttons,$disabled,$action);
1.1       raeburn   340:     if ($context eq 'examblock') {
                    341:         my $maps_elem = 'docs_maps_'.$block;
                    342:         my $res_elem = 'docs_resources_'.$block;
                    343:         $onsubmit = ' onsubmit="return writeToOpener('."'$maps_elem','$res_elem'".');"';
1.7       raeburn   344:         $info = &mt('Items in '.lc($crstype).' for which access will be blocked.');
1.14      raeburn   345:         if ($readonly) {
                    346:             $disabled = ' disabled="disabled"';
                    347:         }
1.1       raeburn   348:     }
1.7       raeburn   349:     if ($context eq 'dumpdocs') {
                    350:         $info = '<span class="LC_fontsize_medium">'.
1.11      bisitz    351:                 &mt('Choose the uploaded course items and templated pages/problems to be copied to Authoring Space.').
1.7       raeburn   352:                 '</span><br /><br />';
                    353:         $startcount = 3 + $numhome;
1.15      raeburn   354:         $onsubmit = ' onsubmit="return checkUnique(document.'.$formname.',document.'.$formname.'.'.$chkname.');"';
                    355:     } elsif ($context eq 'shorturls') {
                    356:         $info = '<span class="LC_fontsize_medium">'.
                    357:                 &mt('Choose the resource(s) and/or folder(s) from Main Content for which shortened URL(s) are needed.').
                    358:                 '</span><br /><br />';
1.7       raeburn   359:     } elsif ($context eq 'imsexport') {
                    360:         $info = &mt('Choose which items you wish to export from your '.$crstype.'.');
1.1       raeburn   361:         $startcount = 5;
1.19    ! raeburn   362:     } elsif ($context eq 'passback') {
        !           363:         $action = '/adm/grades';
        !           364:         $info = '<p>'.
        !           365:                 &mt('Select link-protected launch item for which scores should be sent to launcher CMS, then push Next [_1].',
        !           366:                     '&rarr;').
        !           367:                 '</p><br />';
        !           368:         if ($readonly) {
        !           369:             $disabled = ' disabled="disabled"';
        !           370:         }
1.1       raeburn   371:     }
1.14      raeburn   372:     if ($disabled) {
                    373:         $togglebuttons = '<br />';
1.19    ! raeburn   374:     } elsif ($context ne 'passback') {
1.14      raeburn   375:         $togglebuttons = '<input type="button" value="'.&mt('check all').'" '.
1.15      raeburn   376:                          'onclick="javascript:checkAll(document.'.$formname.'.'.$chkname.')" />'.
1.14      raeburn   377:                          '&nbsp;&nbsp;<input type="button" value="'.&mt('uncheck all').'"'.
1.15      raeburn   378:                          ' onclick="javascript:uncheckAll(document.'.$formname.'.'.$chkname.')" />';
1.14      raeburn   379:     }
1.19    ! raeburn   380:     $display = '<form name="'.$formname.'" action="'.$action.'" method="post"'.$onsubmit.'>'."\n";
1.1       raeburn   381:     if ($context eq 'imsexport') {
1.7       raeburn   382:         $display .= $info.
                    383:                     '<div class="LC_columnSection">'."\n".
1.1       raeburn   384:                     '<fieldset>'.
1.7       raeburn   385:                     '<legend>'.&mt('Content items').'</legend>'."\n".
                    386:                     $togglebuttons.
                    387:                     '</fieldset>';
                    388:         %discussiontime = &Apache::lonnet::dump('discussiontimes',$cdom,$cnum);
1.1       raeburn   389:         $numdisc = keys(%discussiontime);
                    390:         if ($numdisc > 0) {
                    391:             $display .= 
                    392:                 '<fieldset>'.
                    393:                 '<legend>'.&mt('Discussion posts').'</legend>'.
                    394:                 '<input type="button" value="'.&mt('check all').'"'.
                    395:                 ' onclick="javascript:checkAll(document.'.$formname.'.discussion)" />'.
                    396:                 '&nbsp;&nbsp;<input type="button" value="'.&mt('uncheck all').'"'.
                    397:                 ' onclick="javascript:uncheckAll(document.'.$formname.'.discussion)" />'.
1.2       raeburn   398:                 '</fieldset>';
1.1       raeburn   399:         }
1.7       raeburn   400:         $display .= '</div>';
1.19    ! raeburn   401:     } elsif (($context eq 'examblock') || ($context eq 'shorturls') || ($context eq 'passback')) {
1.7       raeburn   402:         $display .= $info.$togglebuttons;
                    403:     } elsif ($context eq 'dumpdocs') {
                    404:         $display .= $preamble.
                    405:                     '<div class="LC_left_float">'.
                    406:                     '<fieldset>'.
                    407:                     '<legend>'.&mt('Content to copy').('&nbsp;'x4).$togglebuttons.'</legend>'.
                    408:                     $info;
1.1       raeburn   409:     }
                    410:     my $lastcontainer = $startcount;
                    411:     $display .= &Apache::loncommon::start_data_table()
                    412:                .&Apache::loncommon::start_data_table_header_row();
                    413:     if ($context eq 'imsexport') {
                    414:         $display .= '<th>'.&mt('Export content item?').'</th>';
                    415:         if ($numdisc > 0) {
                    416:             $display .= '<th>'.&mt('Export discussion posts?').'</th>';
                    417:         }
                    418:     } elsif ($context eq 'examblock') {
                    419:         $display .= '<th>'.&mt('Access blocked?').'</th>';
1.7       raeburn   420:     } elsif ($context eq 'dumpdocs') {
                    421:         $display .= '<th>'.&mt('Copy?').'</th>'.
1.15      raeburn   422:                     '<th>'.&mt("Title in $crstype").'</th>'.
1.7       raeburn   423:                     '<th>'.&mt('Internal Identifier').'</th>'.
                    424:                     '<th>'.&mt('Save as ...').'</th>';
1.15      raeburn   425:     } elsif ($context eq 'shorturls') {
                    426:         $display .= '<th colspan="2">'.&mt('Tiny URL').'</th>'.
                    427:                     '<th>'.&mt("Title in $crstype").'</th>';
1.19    ! raeburn   428:     } elsif ($context eq 'passback') {
        !           429:         $display .= '<th>'.&mt("Title in $crstype").'</th>'.
        !           430:                     '<th>'.&mt('Tiny URL Deep-link').'</th>'.
        !           431:                     '<th>'.&mt('Launcher').'</th>'.
        !           432:                     '<th  style="padding-left: 6px; padding-right: 6px">'.&mt('Score Type').'</th>'.
        !           433:                     '<th style="padding-left: 6px; padding-right: 6px">'.&mt('Select').'</th>';
1.1       raeburn   434:     }
                    435:     $display .= &Apache::loncommon::end_data_table_header_row();
                    436:     while ($curRes = $it->next()) {
                    437:         if ($curRes == $it->BEGIN_MAP()) {
                    438:             $depth++;
                    439:             $parent{$depth} = $lastcontainer;
                    440:         }
                    441:         if ($curRes == $it->END_MAP()) {
                    442:             $depth--;
                    443:             $lastcontainer = $parent{$depth};
                    444:         }
                    445:         if (ref($curRes)) {
                    446:             my $symb = $curRes->symb();
                    447:             my $ressymb = $symb;
1.7       raeburn   448:             if ($context eq 'dumpdocs') {
                    449:                 next unless (($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(docs|supplemental|simplepage)}) ||
                    450:                              ($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(default|supplemental)_\d+\.(sequence|page)}) ||
                    451:                              ($curRes->src() eq '/res/lib/templates/simpleproblem.problem') ||
                    452:                              ($curRes->src() =~ m{^/adm/$match_domain/$match_username/\d+/smppg}));
                    453:             } elsif ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
1.1       raeburn   454:                 unless ($ressymb =~ m|adm/wrapper/adm|) {
                    455:                     $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
                    456:                 }
                    457:             }
1.7       raeburn   458:             $count ++;
1.19    ! raeburn   459:             my ($currelem,$mapurl,$is_map,$showitem);
1.7       raeburn   460:             if ($context eq 'imsexport') {
                    461:                 $currelem = $count+$boards+$startcount;
                    462:             } else {
                    463:                 $currelem = $count+$startcount;
                    464:             }
1.1       raeburn   465:             if (($curRes->is_sequence()) || ($curRes->is_page())) {
                    466:                 $lastcontainer = $currelem;
1.15      raeburn   467:                 $mapurl = (&Apache::lonnet::decode_symb($symb))[2];
                    468:                 $is_map = 1;
                    469:             }
1.19    ! raeburn   470:             if ($context eq 'passback') {
        !           471:                 if (($curRes->is_sequence()) || ($curRes->is_page())) {
        !           472:                     next unless ($shownmaps{$curRes->src});
        !           473:                 } else {
        !           474:                     next unless ($shownsymbs{$symb});
        !           475:                 }
        !           476:             } else {
        !           477:                 $display .= &Apache::loncommon::start_data_table_row()."\n";
        !           478:             }
1.15      raeburn   479:             if ($context eq 'shorturls') {
                    480:                 if ($shorturls{$symb}) {
                    481:                     $display .= '<td>&nbsp;</td><td align="right"><b>'."/tiny/$cdom/$shorturls{$symb}".'</b></td>'."\n";
                    482:                 } else {
                    483:                     $display .= '<td align="left"><label><input type="checkbox" name="'.$chkname.'" '.
                    484:                                 'value="'.$count.'"'.$disabled.' />'.&mt('Add').'</label></td>'.
                    485:                                 '<td>&nbsp;</td>'."\n";
1.1       raeburn   486:                 }
1.19    ! raeburn   487:             } elsif ($context ne 'passback') {
1.15      raeburn   488:                 $display .= '<td><input type="checkbox" name="'.$chkname.'" value="'.$count.'" ';
                    489:                 if ($is_map) {
                    490:                     $display .= 'onclick="javascript:checkFolder(document.'.$formname.','."'$currelem'".')" ';
                    491:                     if ($currmaps{$mapurl}) {
                    492:                         $display .= 'checked="checked"';
                    493:                         push(@checked_maps,$currelem);
                    494:                     }
                    495:                 } else {
                    496:                     if ($curRes->is_problem()) {
1.19    ! raeburn   497:                         $numprobs ++;
1.15      raeburn   498:                     }
                    499:                     $display .= 'onclick="javascript:checkResource(document.'.$formname.','."'$currelem'".')" ';
                    500:                     if ($currresources{$symb}) {
                    501:                         $display .= 'checked="checked"';
                    502:                     }
1.1       raeburn   503:                 }
1.15      raeburn   504:                 $display .= $disabled.' />'."\n";
1.1       raeburn   505:             }
1.7       raeburn   506:             if ($context eq 'dumpdocs') {
                    507:                 $display .= '</td><td valign="top">';
1.15      raeburn   508:             } elsif ($context eq 'shorturls') {
                    509:                 $display .= '<td valign="top">';
1.7       raeburn   510:             }
1.1       raeburn   511:             for (my $i=0; $i<$depth; $i++) {
1.19    ! raeburn   512:                 $showitem .= "$whitespace\n";
1.1       raeburn   513:             }
                    514:             my $icon = 'src="'.$location.'/unknown.gif" alt=""';
                    515:             if ($curRes->is_sequence()) {
1.4       bisitz    516:                 $icon = 'src="'.$location.'/navmap.folder.open.gif" alt="'.&mt('Folder').'"';
1.1       raeburn   517:             } elsif ($curRes->is_page()) {
                    518:                 $icon = 'src="'.$location.'/navmap.page.open.gif" alt="'.&mt('Composite Page').'"';
                    519:             } elsif ($curRes->is_problem()) {
                    520:                 $icon = 'src="'.$location.'/problem.gif" alt="'.&mt('Problem').'"';
                    521:             } elsif ($curRes->is_task()) {
                    522:                 $icon = 'src="'.$location.'/task.gif" alt="'.&mt('Task').'"';
                    523:             } elsif ($curRes->src ne '') {
                    524:                 $icon = 'src="'.&Apache::loncommon::icon($curRes->src).'" alt=""';
                    525:             }
1.19    ! raeburn   526:             $showitem .= '<img '.$icon.' />&nbsp;'."\n";
1.1       raeburn   527:             $children{$parent{$depth}} .= $currelem.':';
                    528:             if ($context eq 'examblock') {
                    529:                 if ($parent{$depth} > 1) {
                    530:                     if ($hierarchy{$parent{$depth}}) {
                    531:                         $hierarchy{$currelem} = $hierarchy{$parent{$depth}}.",'$parent{$depth}'";
                    532:                     } else {
                    533:                         $hierarchy{$currelem} = "'$parent{$depth}'";
                    534:                     }
                    535:                 }
                    536:             }
1.19    ! raeburn   537:             $showitem .= '&nbsp;'.$curRes->title().$whitespace;
        !           538:             if ($context eq 'passback') {
        !           539:                 if ((exists($pb{$symb})) && (ref($pb{$symb}) eq 'HASH')) {
        !           540:                     my $numlinks = scalar(keys(%{$pb{$symb}}));
        !           541:                     my $count = 0;
        !           542:                     foreach my $launcher (sort(keys(%{$pb{$symb}}))) {
        !           543:                         if ($count == 0) {
        !           544:                             $display .= &Apache::loncommon::start_data_table_row()."\n";
        !           545:                             if ($numlinks > 1) {
        !           546:                                 $display .= '<td rowspan="'.$numlinks.'">'.$showitem.'</td>';
        !           547:                             } else {
        !           548:                                 $display .= '<td style="vertical-align: baseline">'.$showitem.'</td>';
        !           549:                             }
        !           550:                         } else {
        !           551:                             $display .= &Apache::loncommon::end_data_table_row().
        !           552:                                         &Apache::loncommon::start_data_table_row()."\n";
        !           553:                         }
        !           554:                         my ($linkuri,$linkprotector,$scope) = split("\0",$launcher);
        !           555:                         my ($ltinum,$ltitype) = ($linkprotector =~ /^(\d+)(c|d)$/);
        !           556:                         my ($appname,$setter);
        !           557:                         if ($ltitype eq 'c') {
        !           558:                             my %lti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider');
        !           559:                             if (ref($lti{$ltinum}) eq 'HASH') {
        !           560:                                 $appname = $lti{$ltinum}{'name'};
        !           561:                                 if ($appname) {
        !           562:                                     $setter = ' (defined in course)';
        !           563:                                 }
        !           564:                             }
        !           565:                         } elsif ($ltitype eq 'd') {
        !           566:                             my %lti = &Apache::lonnet::get_domain_lti($cdom,'linkprot');
        !           567:                             if (ref($lti{$ltinum}) eq 'HASH') {
        !           568:                                 $appname = $lti{$ltinum}{'name'};
        !           569:                                 if ($appname) {
        !           570:                                     $setter = ' (defined in domain)';
        !           571:                                 }
        !           572:                             }
        !           573:                         }
        !           574:                         my $shownscope;
        !           575:                         if ($scope eq 'res') {
        !           576:                             $shownscope = &mt('Resource');
        !           577:                         } elsif ($scope eq 'map') {
        !           578:                             $shownscope = &mt('Folder');
        !           579:                         }  elsif ($scope eq 'rec') {
        !           580:                             $shownscope = &mt('Folder + sub-folders');
        !           581:                         }
        !           582:                         $display .= '<td style="vertical-align: baseline"><span style="font-weight: bold;">'.$linkuri.'</span></td>'."\n".
        !           583:                                     '<td style="vertical-align: baseline; padding-left: 6px; padding-right: 6px">'.$appname.$setter.'</td>'."\n".
        !           584:                                     '<td style="vertical-align: baseline"><span style="font-style: italic;">'.$shownscope.'</span></td>'."\n".
        !           585:                                     '<td align="right" style="vertical-align: baseline"><input type="radio" name="'.$chkname.'" '.
        !           586:                                     'value="'.&escape($launcher).'"'.$disabled.' /></td>'."\n";
        !           587:                         $count ++;
        !           588:                     }
        !           589:                 } else {
        !           590:                     $display .= &Apache::loncommon::start_data_table_row()."\n".
        !           591:                                 '<td colspan="5">'.$showitem.'</td>';
        !           592:                 }
        !           593:             } else {
        !           594:                 $display .= $showitem.'</td>'."\n";
        !           595:             }
1.1       raeburn   596:             if ($context eq 'imsexport') {
                    597: # Existing discussion posts?
                    598:                 if ($discussiontime{$ressymb} > 0) {
                    599:                     $boards ++;
                    600:                     $display .= '<td align="right">'
                    601:                                .'<input type="checkbox" name="discussion" value="'.$count.'" />'
                    602:                                .'</td>'."\n";
                    603:                 } elsif ($numdisc > 0) {
                    604:                     $display .= '<td>&nbsp;</td>'."\n";
                    605:                 }
1.7       raeburn   606:             } elsif ($context eq 'dumpdocs') {
                    607:                 my $src = $curRes->src();
                    608:                 my ($filepath,$title);
                    609:                 if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E}) {
                    610:                     $filepath = &Apache::lonnet::filelocation('',$src);
                    611:                     $filepath =~ s/\Q$crsprefix\E//;
                    612:                     if ($curRes->is_map()) {
                    613:                         $title = $files{$filepath};
                    614:                     } else {
                    615:                         $filepath =~ s{docs/}{}; 
                    616:                         $title = $filepath;
                    617:                         $title =~ s{^(default|\d+)/\d*/?}{};
                    618:                     }
                    619:                 } else {
                    620:                     $title = $curRes->title();
                    621:                     $title =~ s{/}{_}g;
                    622:                     $title = &clean($title);
                    623:                     if ($src eq '/res/lib/templates/simpleproblem.problem') {
                    624:                         my ($map,$id,$res) = &Apache::lonnet::decode_symb($symb);
                    625:                         $map =~ s{^uploaded/$cdom/$cnum/}{};
                    626:                         $filepath = $map.'_'.$id;
                    627:                         $title .= '.problem';
                    628:                     } elsif ($src =~ m{^/adm/$match_domain/$match_username/(\d+)/smppg}) {
                    629:                         $filepath = 'smppage_'.$1.'.db';
                    630:                         $title .= '.html';
                    631:                     }
                    632:                 }
                    633:                 $display .= '<td>'.$filepath.'</td>'.
                    634:                             '<td><input type="text" size="40" name="namefor_'.$count.'" id="namefor_'.$count.'" value="'.$title.'" /></td>'."\n";
1.1       raeburn   635:             }
                    636:             $display .= &Apache::loncommon::end_data_table_row();
                    637:         }
                    638:     }
                    639:     $display .= &Apache::loncommon::end_data_table();
                    640:     if ($context eq 'imsexport') {
                    641:         if ($numprobs > 0) {
                    642:             $display .= '<p><span class="LC_nobreak">'.
                    643:                         &mt('Export format for LON-CAPA problems:').
                    644:                         '<label><input type="radio" name="format" value="xml" checked="checked" />'.
                    645:                         '&nbsp;'.&mt('XML').'</label>'.('&nbsp;' x3).
                    646:                         '<label><input type="radio" name="format" value="html" />'.
                    647:                         '&nbsp;'.&mt('HTML').'</label>'.('&nbsp;' x3).
                    648:                         '<label><input type="radio" name="format" value="plaintext" />'.
                    649:                         '&nbsp;'.&mt('Text').'</label></span></p>';
                    650:         }
                    651:     }
1.7       raeburn   652:     my $numcount;
1.1       raeburn   653:     if ($context eq 'imsexport') {
                    654:         $display .= 
1.7       raeburn   655:            '<p>'.
1.1       raeburn   656:            '<input type="hidden" name="finishexport" value="1" />'.
                    657:            '<input type="submit" name="exportcourse" value="'.
1.7       raeburn   658:            &mt('Export').'" /></p>';
                    659:         $numcount = $count + $boards + $startcount;
1.1       raeburn   660:     } elsif ($context eq 'examblock') {
1.14      raeburn   661:         unless ($readonly) {
                    662:             $display .=
                    663:                 '<p>'.
                    664:                 '<input type="submit" name="resourceblocks" value="'.
                    665:                 &mt('Copy Choices to Main Window').'" /></p>';
                    666:         }
1.7       raeburn   667:         $numcount = $count + $startcount;
                    668:     } elsif ($context eq 'dumpdocs') {
                    669:         $display .= '</fieldset>'.
                    670:                     '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'.
                    671:                     '<div>'.
1.8       raeburn   672:                     '<input type="submit" name="dumpcourse" value="'.&mt("Copy $crstype Content").'" />'.
1.7       raeburn   673:                     '</div>';
                    674:         $numcount = $count + $startcount;
1.15      raeburn   675:     } elsif ($context eq 'shorturls') {
                    676:         unless ($readonly) {
                    677:             $display .=
                    678:                 '<p>'.
                    679:                 '<input type="submit" name="shorturls" value="'.
                    680:                 &mt('Create Tiny URL(s)').'" /></p>';
                    681:         }
1.19    ! raeburn   682:     } elsif ($context eq 'passback') {
        !           683:         unless ($readonly) {
        !           684:             $display .=
        !           685:                 '<p>'.
        !           686:                 '<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($env{'form.symb'}).'" />'."\n".
        !           687:                 '<input type="hidden" name="command" value="passback" />'.
        !           688:                 '<input type="submit" name="picklauncher" value="'.
        !           689:                 &mt('Next').' &rarr;" /></p>';
        !           690:         }
1.1       raeburn   691:     }
1.7       raeburn   692:     $display .= '</form>';
1.19    ! raeburn   693:     if ($context eq 'passback') {
        !           694:         return $display;
        !           695:     }
1.17      raeburn   696:     my $scripttag =
1.1       raeburn   697:         &respicker_javascript($startcount,$numcount,$context,$formname,\%children,
1.15      raeburn   698:                               \%hierarchy,\@checked_maps,$numhome,$chkname);
                    699:     if (($context eq 'dumpdocs') || ($context eq 'shorturls')) {
1.7       raeburn   700:         return $scripttag.$display; 
                    701:     }
1.1       raeburn   702:     my ($title,$crumbs,$args);
1.7       raeburn   703:     if ($context eq 'imsexport') { 
1.1       raeburn   704:         $title = 'Export '.$crstype.' to IMS Package';
                    705:     } elsif ($context eq 'examblock') {
                    706:         $title = 'Resources with Access blocked';
                    707:         $args = {'only_body'      => 1,
                    708:                  'add_entries' => { onload => 'javascript:recurseFolders();' }, 
                    709:                 };
                    710:     }
1.3       raeburn   711:     $output = &Apache::loncommon::start_page($title,$scripttag,$args);
1.1       raeburn   712:     if ($context eq 'imsexport') {
1.2       raeburn   713:         $output .= &Apache::lonhtmlcommon::breadcrumbs('IMS Export').
                    714:                    &Apache::londocs::startContentScreen('tools');
1.7       raeburn   715:     } elsif ($context eq 'dumpdocs') {
1.15      raeburn   716:         $output .= &Apache::lonhtmlcommon::breadcrumbs('Copying to Authoring Space').
                    717:                    &Apache::londocs::startContentScreen('tools');
1.1       raeburn   718:     }
                    719:     $output .= $display;
                    720:     if ($context eq 'examblock') {
                    721:         $output .= &Apache::loncommon::end_page();
1.2       raeburn   722:     } elsif ($context eq 'imsexport') {
                    723:         $output .= &Apache::londocs::endContentScreen();
1.1       raeburn   724:     }
                    725:     return $output;
                    726: }
                    727: 
                    728: sub respicker_javascript {
                    729:     my ($startcount,$numitems,$context,$formname,$children,$hierarchy,
1.15      raeburn   730:         $checked_maps,$numhome,$chkname) = @_;
                    731:     my $check_uncheck = <<"FIRST";
1.1       raeburn   732: function checkAll(field) {
                    733:     if (field.length > 0) {
                    734:         for (i = 0; i < field.length; i++) {
                    735:             field[i].checked = true ;
                    736:         }
                    737:     } else {
                    738:         field.checked = true
                    739:     }
                    740: }
                    741: 
                    742: function uncheckAll(field) {
                    743:     if (field.length > 0) {
                    744:         for (i = 0; i < field.length; i++) {
                    745:             field[i].checked = false;
                    746:         }
                    747:     } else {
                    748:         field.checked = false;
                    749:     }
                    750: }
1.15      raeburn   751: FIRST
                    752:     if ($context eq 'shorturls') {
                    753:         return <<"END";
                    754: <script type="text/javascript">
                    755: // <![CDATA[
                    756: $check_uncheck
                    757: // ]]>
                    758: </script>
                    759: END
                    760:     }
                    761:     return unless ((ref($children) eq 'HASH') && (ref($hierarchy) eq 'HASH')
                    762:                    && (ref($checked_maps) eq 'ARRAY'));
                    763:     my ($elem,$nested,$nameforelem);
                    764:     if ($context eq 'dumpdocs') {
                    765:         $elem='((parseInt(item)-'.$startcount.')*2)+'.$startcount;
                    766:         $nested='((parseInt(nesting[item][i])-'.$startcount.')*2)+'.$startcount;
                    767:         $nameforelem=$elem+1;
                    768:     } else {
                    769:         $elem='parseInt(item)';
                    770:         $nested='parseInt(nesting[item][i])';
                    771:     }
                    772:     my $scripttag = <<"START";
                    773: <script type="text/javascript">
                    774: // <![CDATA[
                    775: $check_uncheck
1.1       raeburn   776: 
                    777: function checkFolder(form,item) {
1.7       raeburn   778:     var elem = $elem;
                    779:     if (form.elements[elem].checked == true) {
1.1       raeburn   780:         containerCheck(form,item);
                    781:     } else {
                    782:         containerUncheck(form,item);
                    783:     }
                    784: }
                    785: 
                    786: function checkResource(form,item) {
1.7       raeburn   787:     var elem = $elem;
                    788:     if (form.elements[elem].checked == false) {
1.1       raeburn   789:         containerUncheck(form,item);
                    790:     }
                    791: }
                    792: 
                    793: numitems = $numitems;
                    794: var parents = new Array(numitems);
                    795: var nesting = new Array(numitems);
                    796: var initial = new Array();
                    797: for (var i=$startcount; i<numitems; i++) {
                    798:     parents[i] = new Array();
                    799:     nesting[i] = new Array();
                    800: }
                    801: 
                    802: START
                    803: 
                    804:     foreach my $container (sort { $a <=> $b } (keys(%{$children}))) {
                    805:         my @contents = split(/:/,$children->{$container});
                    806:         for (my $i=0; $i<@contents; $i ++) {
                    807:             $scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
                    808:         }
                    809:     }
                    810: 
                    811:     if ($context eq 'examblock') {
                    812:         foreach my $item (sort { $a <=> $b } (keys(%{$hierarchy}))) {
                    813:             $scripttag .= "nesting[$item] = new Array($hierarchy->{$item});\n";
                    814:         }
                    815:          
                    816:         my @sorted_maps = sort { $a <=> $b } (@{$checked_maps});
                    817:         for (my $i=0; $i<@sorted_maps; $i++) {
                    818:             $scripttag .= "initial[$i] = '$sorted_maps[$i]'\n";
                    819:         }
                    820:         $scripttag .= <<"EXTRA";
                    821: 
                    822: function recurseFolders() {
                    823:     if (initial.length > 0) {
                    824:         for (var i=0; i<initial.length; i++) {
                    825:             containerCheck(document.$formname,initial[i]);
                    826:         }
                    827:     }
                    828:     return;
                    829: }
                    830: 
                    831: EXTRA
1.7       raeburn   832:     } elsif ($context eq 'dumpdocs') {
                    833:         my $blankmsg = &mt('An item selected has no filename set in the "Save as ..." column.');
                    834:         my $dupmsg = &mt('Items selected for copying need unique filenames in the "Save as ..." column.');
1.11      bisitz    835:         my $homemsg = &mt('An Authoring Space needs to be selected.');
1.13      damieng   836:         &js_escape(\$blankmsg);
                    837:         &js_escape(\$dupmsg);
                    838:         &js_escape(\$homemsg);
1.7       raeburn   839:         $scripttag .= <<"EXTRA";
                    840: 
                    841: function checkUnique(form,field) {
                    842:     var duplicate = 0;
                    843:     var blank = 0;
1.9       raeburn   844:     var numhome = '$numhome';
1.7       raeburn   845:     if (field.length > 0) {
                    846:         for (i=0; i<field.length; i++) {
                    847:             if (field[i].checked) {
                    848:                 var item = field[i].value;
                    849:                 var namefor = document.getElementById('namefor_'+item);
                    850:                 if (namefor) {
                    851:                     var possval = namefor.value;
                    852:                     if (!possval) {
                    853:                         blank = item;
                    854:                         break;
                    855:                     }
                    856:                     for (j=i+1; j<field.length; j++) {
                    857:                         if (field[j].checked) {
                    858:                             var curritem = field[j].value;
                    859:                             var currnamefor = document.getElementById('namefor_'+curritem);
                    860:                             if (currnamefor) {
                    861:                                 var currval = currnamefor.value;
                    862:                                 if (currval == possval) {
                    863:                                     duplicate = curritem;
                    864:                                     break;
                    865:                                 }
                    866:                             }
                    867:                         }
                    868:                     }
                    869:                     if (duplicate) {
                    870:                         break;
                    871:                     }
                    872:                 }
                    873:             }
                    874:         }
                    875:     }
                    876:     if (blank) {
                    877:         alert('$blankmsg');
                    878:         return false;
                    879:     }
                    880:     if (duplicate) {
                    881:         alert('$dupmsg');
                    882:         return false;
                    883:     }
1.9       raeburn   884:     if (numhome > 1) {
                    885:         if (!form.authorspace.options[form.authorspace.selectedIndex].value) {
                    886:             alert('$homemsg');
                    887:             return false;
                    888:         }
                    889:     }
1.7       raeburn   890:     return true;
                    891: }
                    892: 
                    893: EXTRA
                    894: 
1.1       raeburn   895:     }
                    896: 
                    897:     $scripttag .= <<"END";
                    898: 
                    899: function containerCheck(form,item) {
1.7       raeburn   900:     var elem = $elem;
                    901:     form.elements[elem].checked = true;
1.1       raeburn   902:     if(Object.prototype.toString.call(parents[item]) === '[object Array]') {
                    903:         if (parents[item].length > 0) {
                    904:             for (var j=0; j<parents[item].length; j++) {
                    905:                 containerCheck(form,parents[item][j]);
                    906:             }
                    907:         }
                    908:     }
                    909: }
                    910: 
                    911: function containerUncheck(form,item) {
                    912:     if(Object.prototype.toString.call(nesting[item]) === '[object Array]') {
                    913:         if (nesting[item].length > 0) {
                    914:             for (var i=0; i<nesting[item].length; i++) {
1.7       raeburn   915:                 var nested = $nested;
1.1       raeburn   916:             }
                    917:         }
                    918:     }
                    919:     return;
                    920: }
                    921: 
                    922: END
                    923: 
                    924:     if ($context eq 'examblock') {
                    925:         $scripttag .= <<ENDEX;
                    926: function writeToOpener(maps,resources) {
                    927:     var checkedmaps = '';
                    928:     var checkedresources = '';
1.15      raeburn   929:     for (var i=0; i<document.$formname.${chkname}.length; i++) {
                    930:         if (document.$formname.${chkname}[i].checked) {
1.1       raeburn   931:             var isResource = 1;
                    932:             var include = 1;
                    933:             var elemnum = i+1+$startcount;
                    934:             if (Object.prototype.toString.call(parents[elemnum]) === '[object Array]') {
                    935:                 if (parents[elemnum].length > 0) {
                    936:                     isResource = 0;
                    937:                 }
                    938:             }
                    939:             if (isResource == 1) {
1.12      raeburn   940:                 if (nesting[elemnum] != null) {
                    941:                     if (nesting[elemnum].length > 0) {
                    942:                         var lastelem = nesting[elemnum].length-1;
                    943:                         if (document.$formname.elements[nesting[elemnum][lastelem]].checked) {
                    944:                             include = 0;
                    945:                         }
1.1       raeburn   946:                     }
                    947:                 }
                    948:             }
                    949:             if (include == 1) {
                    950:                 if (isResource == 1) {
1.15      raeburn   951:                     checkedresources += document.$formname.${chkname}[i].value+',';
1.1       raeburn   952:                 } else {
1.15      raeburn   953:                     checkedmaps += document.$formname.${chkname}[i].value+',';
1.1       raeburn   954:                 }
                    955:             }
                    956:         }
                    957:     }
                    958:     opener.document.getElementById(maps).value = checkedmaps;
                    959:     opener.document.getElementById(resources).value = checkedresources;
                    960:     window.close();
                    961:     return false;
                    962: }
                    963: 
                    964: ENDEX
                    965:     }
                    966: 
                    967:     $scripttag .= '
                    968: // ]]>
                    969: </script>
                    970: ';
                    971:     return $scripttag;
                    972: }
                    973: 
                    974: sub get_navmap_object {
                    975:     my ($crstype,$context) = @_;
                    976:     my $navmap = Apache::lonnavmaps::navmap->new();
                    977:     my $outcome;
                    978:     if (!defined($navmap)) {
                    979:         if ($context eq 'imsexport') {
                    980:             $outcome = &Apache::loncommon::start_page('Export '.$crstype.' to IMS Package').
                    981:                       '<h2>'.&mt('IMS Export Failed').'</h2>';
                    982:         } elsif ($context eq 'examblock') {
                    983:             $outcome = &Apache::loncommon::start_page('Selection of Resources for Blocking',
                    984:                                                        undef,{'only_body' => 1,}).
                    985:                       '<h2>'.&mt('Resource Display Failed').'</h2>';  
1.7       raeburn   986:         } elsif ($context eq 'dumpdocs') {
1.15      raeburn   987:             $outcome = '<h2>'.&mt('Copying to Authoring Space unavailable').'</h2>';
                    988:         } elsif ($context eq 'shorturls') {
                    989:             $outcome = '<h2>'.&mt('Display/Setting of shortened URLs unavailable').'</h2>';
1.7       raeburn   990:         }
1.1       raeburn   991:         $outcome .= '<div class="LC_error">';
                    992:         if ($crstype eq 'Community') {
                    993:             $outcome .= &mt('Unable to retrieve information about community contents');
                    994:         } else {
                    995:             $outcome .= &mt('Unable to retrieve information about course contents');
                    996:         }
                    997:         $outcome .= '</div>';
1.15      raeburn   998:         if (($context eq 'imsexport') || ($context eq 'dumpdocs') || ($context eq 'shorturls') ) {
1.1       raeburn   999:             $outcome .= '<a href="/adm/coursedocs">';
                   1000:             if ($crstype eq 'Community') {
                   1001:                 $outcome .= &mt('Return to Community Editor');
                   1002:             } else {
                   1003:                 $outcome .= &mt('Return to Course Editor');
                   1004:             }
                   1005:             $outcome .= '</a>';
1.7       raeburn  1006:             if ($context eq 'imsexport') {
                   1007:                 &Apache::lonnet::logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
1.17      raeburn  1008:             } elsif ($context eq 'dumpdocs') {
1.8       raeburn  1009:                 &Apache::lonnet::logthis('Copying to Authoring Space failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
1.17      raeburn  1010:             } elsif ($context eq 'shorturls') {
                   1011:                 &Apache::lonnet::logthis('Displaying and/or saving URL shortcuts failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
1.7       raeburn  1012:             }
1.1       raeburn  1013:         } elsif ($context eq 'examblock') {
                   1014:             $outcome .=  '<href="javascript:window.close();">'.&mt('Close window').'</a>';         
                   1015:         }
                   1016:         return (undef,$outcome);
                   1017:     } else {
                   1018:         return ($navmap);
                   1019:     }
                   1020: }
                   1021: 
1.7       raeburn  1022: sub clean {
                   1023:     my ($title)=@_;
                   1024:     $title=~s/[^\w\/\!\$\%\^\*\-\_\=\+\;\:\,\\\|\`\~]+/\_/gs;
                   1025:     return $title;
                   1026: }
                   1027: 
                   1028: sub enumerate_course_contents {
                   1029:     my ($navmap,$map_url,$resource_symb,$titleref,$context,$cdom,$cnum) = @_;
                   1030:     if ((ref($navmap)) && (ref($map_url) eq 'HASH') &&
                   1031:         (ref($resource_symb) eq 'HASH') && (ref($titleref) eq 'HASH')) {
                   1032:         my $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
                   1033:         my $count = 0;
                   1034:         while (my $curRes = $it->next()) {
                   1035:             if (ref($curRes)) {
                   1036:                 my $symb = $curRes->symb();
                   1037:                 my $ressymb = $symb;
                   1038:                 if ($context eq 'dumpdocs') {
                   1039:                     next unless (($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(docs|supplemental|simplepage)/}) ||
                   1040:                                  ($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(default|supplemental)_\d+\.(sequence|page)}) ||
                   1041:                                  ($curRes->src() eq '/res/lib/templates/simpleproblem.problem') ||
                   1042:                                  ($curRes->src() =~ m{^/adm/$match_domain/$match_username/\d+/smppg}));
                   1043:                 } elsif ($ressymb =~ m{adm/($match_domain)/($match_username)/(\d+)/bulletinboard$}) {
                   1044:                     unless ($ressymb =~ m{adm/wrapper/adm}) {
                   1045:                         $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.
                   1046:                                    '/bulletinboard';
                   1047:                     }
                   1048:                 }
                   1049:                 $count ++;
1.15      raeburn  1050:                 if ($context eq 'shorturls') {
                   1051:                     $resource_symb->{$count} = $ressymb;
1.7       raeburn  1052:                 } else {
1.15      raeburn  1053:                     if (($curRes->is_sequence()) || ($curRes->is_page())) {
                   1054:                         $map_url->{$count} = (&Apache::lonnet::decode_symb($symb))[2];
                   1055:                     } else {
                   1056:                         $resource_symb->{$count} = $ressymb;
                   1057:                     }
1.7       raeburn  1058:                 }
                   1059:                 $titleref->{$count} = $curRes->title();
                   1060:             }
                   1061:         }
                   1062:     }
                   1063:     return;
                   1064: }
                   1065: 
1.1       raeburn  1066: 1;

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