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

1.1       raeburn     1: # The LearningOnline Network
                      2: #
1.4     ! bisitz      3: # $Id: loncourserespicker.pm,v 1.3 2013/01/03 21:06:38 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: 
                     36: loncourserespicker provides an interface for selecting which folders and/or
                     37: resources are to be either:
                     38: 
                     39: (a) exported to an IMS Content Package
                     40: (b) subject to access blocking for the duriation of an exam/quiz.  
                     41: 
                     42: =head1 DESCRIPTION
                     43: 
                     44: This module provides routines to generate a hierarchical display of folders
                     45: and resources in a course which can be selected for specific actions.
                     46: 
                     47: The choice of items is copied back to the main window from which the pop-up
                     48: window used to display the Course Contents was opened.
                     49: 
                     50: =head1 OVERVIEW
                     51: 
                     52: The main subroutine: &create_picker() will display the hierarchy of folders,
                     53: sub-folders, and resources in the Main Course Documents area.  Items can be
                     54: selected using checkboxes, and/or a "Check All" button.  Selection of a folder
                     55: causes the contents of the folder to also be selected automatically. The
                     56: propagation of check status is recursive into sub-folders.  Likewise, if an
                     57: item deep in a nested set of folders and sub-folders is unchecked, the 
                     58: uncheck will propagate up through the hierarchy causing any folders at
                     59: a higher level to become unchecked.
                     60: 
                     61: There is a submit button, which will be named differently according to the 
                     62: content in which resource/folder selection is being made.
                     63: 
                     64: The two contexts currently supported are: IMS export and selection of
                     65: content to be subject to access restructions for the duration of an
                     66: exam.  
                     67: 
                     68: =head1 INTERNAL SUBROUTINES
                     69: 
                     70: =item &create_picker()
                     71: 
                     72: Created HTML mark up to display contents of course with checkboxes to
                     73: select items.  Checking a folder causes recursive checking of items
                     74: within the folder. Unchecking a resource causing unchecking of folders
                     75: containing the item back up to the top level.
                     76: 
                     77: Inputs: 7.
                     78:    - $navmap  -- Reference to LON-CAPA navmap object 
                     79:                 (encapsulates information about resources in the course). 
                     80: 
                     81:    - $context -- Context in which course resource selection is being made.
                     82:                  Currently imsexport and examblock are supported.
                     83: 
                     84:    - $formname  -- Name of the form in the window from which the pop-up
                     85:                    used to select course items was launched. 
                     86: 
                     87:    - $crstype  -- Course or Community
                     88: 
                     89:    - $blockedmaps -- Reference to hash of previously selected maps
                     90:                      (e.g., for a live exam block).   
                     91: 
                     92:    - $blockedresources  -- Reference to hash of resources selected
                     93:                            previously (e.g., for an exam block).  
                     94: 
                     95:    - $block  -- An internal ID (integer) used to track which exam
                     96:                 block currently being configured.
                     97: 
                     98: 
                     99: Output: $output is the HTML mark-up for display/selection of content
                    100:         items in the pop-up window.
                    101: 
                    102: =item &respicker_javascript()
                    103: 
                    104: Creates javascript functions for checking/unchecking all items, and
                    105: for recursive checking triggered by checking a folder, or recursive
                    106: (upeards) unchecking of an item within a folder. 
                    107: 
                    108: Inputs: 7. 
                    109:    - $startcount -- Starting offset of form element numbering for items  
                    110: 
                    111:    - $numcount -- Total numer of folders and resources in course.
                    112: 
                    113:    - $context -- Context in which resources are being displayed
                    114:                  (imsexport or examblock). 
                    115: 
                    116:    - $formname --  Name of form.
                    117: 
                    118:    - $children -- Reference to hash of items contained within a folder. 
                    119: 
                    120:    - $hierarchy -- Reference to hierarchy of folders containing an item.
                    121: 
                    122:    - $checked_maps -- Reference to array of folders currently checked.
                    123: 
                    124: Output: 1. Javascript (witthin <script></script> tags.
                    125: 
                    126: 
                    127: =item &get_navmap_object() 
                    128: 
                    129: Instantiates a navmaps object, and generates an error message if
                    130: no object instantiated.
                    131: 
                    132: Inputs: 2.
                    133:    - $crstype -- Container type: Course or Community
                    134: 
                    135:    - $context -- Context: imsexport or examblock
                    136: 
                    137: =over
                    138: 
                    139: =back
                    140: 
                    141: =cut
                    142: 
                    143: 
                    144: package Apache::loncourserespicker;
                    145: 
                    146: use strict;
                    147: use Apache::lonnet;
                    148: use Apache::loncommon;
                    149: use Apache::lonhtmlcommon;
                    150: use Apache::lonnavmaps;
1.2       raeburn   151: use Apache::londocs;
1.1       raeburn   152: use Apache::lonlocal;
                    153: use LONCAPA qw(:DEFAULT :match);
                    154: 
                    155: sub create_picker {
                    156:     my ($navmap,$context,$formname,$crstype,$blockedmaps,$blockedresources,$block) = @_;
                    157:     return unless (ref($navmap));
                    158:     my ($it,$output,$numdisc,%maps,%resources,%discussiontime,%currmaps,%currresources);
                    159:     $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
                    160:     if (ref($blockedmaps) eq 'HASH') {
                    161:         %currmaps = %{$blockedmaps};
                    162:     }
                    163:     if (ref($blockedresources) eq 'HASH') {
                    164:         %currresources = %{$blockedresources};
                    165:     }
                    166:     my @checked_maps;
                    167:     my $curRes;
                    168:     my $numprobs = 0;
                    169:     my $depth = 0;
                    170:     my $count = 0;
                    171:     my $boards = 0;
                    172:     my $startcount = 1;
                    173:     my %parent = ();
                    174:     my %children = ();
                    175:     my %hierarchy = ();
                    176:     my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons");
                    177:     my $whitespace = 
                    178:         '<img src="'.$location.'/whitespace_21.gif" class="LC_docs_spacer" alt="" />';
                    179: 
                    180:     my $onsubmit;
                    181:     if ($context eq 'examblock') {
                    182:         my $maps_elem = 'docs_maps_'.$block;
                    183:         my $res_elem = 'docs_resources_'.$block;
                    184:         $onsubmit = ' onsubmit="return writeToOpener('."'$maps_elem','$res_elem'".');"';
                    185:     }
                    186:     my $display =
                    187:        '<form name="'.$formname.'" action="" method="post"'.$onsubmit.'>'."\n".
                    188:        '<p>';
                    189:     if ($context eq 'imsexport') {
                    190:         $display .= &mt('Choose which items you wish to export from your '.
                    191:                         $crstype.'.');
                    192:         $startcount = 5;
                    193:     } elsif ($context eq 'examblock') {
                    194:         $display .= &mt('Items in '.lc($crstype).' for which access will be blocked.');
                    195:     }
                    196:     $display .= '</p>';
                    197:     if ($context eq 'imsexport') {
                    198:         $display .= '<div class="LC_columnSection">'."\n".
                    199:                     '<fieldset>'.
                    200:                     '<legend>'.&mt('Content items').'</legend>'."\n";
                    201:     }
                    202:     $display .= 
                    203:         '<input type="button" value="'.&mt('check all').'" '.
                    204:         'onclick="javascript:checkAll(document.'.$formname.'.archive)" />'.
                    205:         '&nbsp;&nbsp;<input type="button" value="'.&mt('uncheck all').'"'.
                    206:         ' onclick="javascript:uncheckAll(document.'.$formname.'.archive)" />';
                    207:     if ($context eq 'imsexport') {
                    208:         $display .= '</fieldset>';
                    209:         %discussiontime =
                    210:             &Apache::lonnet::dump('discussiontimes',
                    211:                                   $env{'course.'.$env{'request.course.id'}.'.domain'},
                    212:                                   $env{'course.'.$env{'request.course.id'}.'.num'});
                    213:         $numdisc = keys(%discussiontime);
                    214:         if ($numdisc > 0) {
                    215:             $display .= 
                    216:                 '<fieldset>'.
                    217:                 '<legend>'.&mt('Discussion posts').'</legend>'.
                    218:                 '<input type="button" value="'.&mt('check all').'"'.
                    219:                 ' onclick="javascript:checkAll(document.'.$formname.'.discussion)" />'.
                    220:                 '&nbsp;&nbsp;<input type="button" value="'.&mt('uncheck all').'"'.
                    221:                 ' onclick="javascript:uncheckAll(document.'.$formname.'.discussion)" />'.
1.2       raeburn   222:                 '</fieldset>';
1.1       raeburn   223:         }
1.2       raeburn   224:         $display .= '</div>';      
1.1       raeburn   225:     }
                    226:     my $lastcontainer = $startcount;
                    227:     $display .= &Apache::loncommon::start_data_table()
                    228:                .&Apache::loncommon::start_data_table_header_row();
                    229:     if ($context eq 'imsexport') {
                    230:         $display .= '<th>'.&mt('Export content item?').'</th>';
                    231:         if ($numdisc > 0) {
                    232:             $display .= '<th>'.&mt('Export discussion posts?').'</th>';
                    233:         }
                    234:     } elsif ($context eq 'examblock') {
                    235:         $display .= '<th>'.&mt('Access blocked?').'</th>';
                    236:     }
                    237:     $display .= &Apache::loncommon::end_data_table_header_row();
                    238:     while ($curRes = $it->next()) {
                    239:         if (ref($curRes)) {
                    240:              $count ++;
                    241:         }
                    242:         if ($curRes == $it->BEGIN_MAP()) {
                    243:             $depth++;
                    244:             $parent{$depth} = $lastcontainer;
                    245:         }
                    246:         if ($curRes == $it->END_MAP()) {
                    247:             $depth--;
                    248:             $lastcontainer = $parent{$depth};
                    249:         }
                    250:         if (ref($curRes)) {
                    251:             my $symb = $curRes->symb();
                    252:             my $ressymb = $symb;
                    253:             if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
                    254:                 unless ($ressymb =~ m|adm/wrapper/adm|) {
                    255:                     $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
                    256:                 }
                    257:             }
                    258:             my $currelem = $count+$boards+$startcount;
                    259:             $display .= &Apache::loncommon::start_data_table_row().
                    260:                        '<td>'."\n".
                    261:                        '<input type="checkbox" name="archive" value="'.$count.'" ';
                    262:             if (($curRes->is_sequence()) || ($curRes->is_page())) {
                    263:                 $lastcontainer = $currelem;
                    264:                 $display .= 'onclick="javascript:checkFolder(this.form,'."'$currelem'".')" ';
                    265:                 my $mapurl = (&Apache::lonnet::decode_symb($symb))[2];
                    266:                 if ($currmaps{$mapurl}) {
                    267:                     $display .= 'checked="checked"';
                    268:                     push(@checked_maps,$currelem);
                    269:                 }
                    270:             } else {
                    271:                 if ($curRes->is_problem()) {
                    272:                     $numprobs ++;
                    273:                 }
                    274:                 $display .= 'onclick="javascript:checkResource(this.form,'."'$currelem'".')" ';
                    275:                 if ($currresources{$symb}) {
                    276:                     $display .= 'checked="checked"';
                    277:                 }
                    278:             }
                    279:             $display .= ' />'."\n";
                    280:             for (my $i=0; $i<$depth; $i++) {
                    281:                 $display .= "$whitespace\n";
                    282:             }
                    283:             my $icon = 'src="'.$location.'/unknown.gif" alt=""';
                    284:             if ($curRes->is_sequence()) {
1.4     ! bisitz    285:                 $icon = 'src="'.$location.'/navmap.folder.open.gif" alt="'.&mt('Folder').'"';
1.1       raeburn   286:             } elsif ($curRes->is_page()) {
                    287:                 $icon = 'src="'.$location.'/navmap.page.open.gif" alt="'.&mt('Composite Page').'"';
                    288:             } elsif ($curRes->is_problem()) {
                    289:                 $icon = 'src="'.$location.'/problem.gif" alt="'.&mt('Problem').'"';
                    290:             } elsif ($curRes->is_task()) {
                    291:                 $icon = 'src="'.$location.'/task.gif" alt="'.&mt('Task').'"';
                    292:             } elsif ($curRes->src ne '') {
                    293:                 $icon = 'src="'.&Apache::loncommon::icon($curRes->src).'" alt=""';
                    294:             }
                    295:             $display .= '<img '.$icon.' />&nbsp;'."\n";
                    296:             $children{$parent{$depth}} .= $currelem.':';
                    297:             if ($context eq 'examblock') {
                    298:                 if ($parent{$depth} > 1) {
                    299:                     if ($hierarchy{$parent{$depth}}) {
                    300:                         $hierarchy{$currelem} = $hierarchy{$parent{$depth}}.",'$parent{$depth}'";
                    301:                     } else {
                    302:                         $hierarchy{$currelem} = "'$parent{$depth}'";
                    303:                     }
                    304:                 }
                    305:             }
                    306:             $display .= '&nbsp;'.$curRes->title().'</td>'."\n";
                    307: 
                    308:             if ($context eq 'imsexport') {
                    309: # Existing discussion posts?
                    310:                 if ($discussiontime{$ressymb} > 0) {
                    311:                     $boards ++;
                    312:                     $display .= '<td align="right">'
                    313:                                .'<input type="checkbox" name="discussion" value="'.$count.'" />'
                    314:                                .'</td>'."\n";
                    315:                 } elsif ($numdisc > 0) {
                    316:                     $display .= '<td>&nbsp;</td>'."\n";
                    317:                 }
                    318:             }
                    319:             $display .= &Apache::loncommon::end_data_table_row();
                    320:         }
                    321:     }
                    322:     $display .= &Apache::loncommon::end_data_table();
                    323:     if ($context eq 'imsexport') {
                    324:         if ($numprobs > 0) {
                    325:             $display .= '<p><span class="LC_nobreak">'.
                    326:                         &mt('Export format for LON-CAPA problems:').
                    327:                         '<label><input type="radio" name="format" value="xml" checked="checked" />'.
                    328:                         '&nbsp;'.&mt('XML').'</label>'.('&nbsp;' x3).
                    329:                         '<label><input type="radio" name="format" value="html" />'.
                    330:                         '&nbsp;'.&mt('HTML').'</label>'.('&nbsp;' x3).
                    331:                         '<label><input type="radio" name="format" value="plaintext" />'.
                    332:                         '&nbsp;'.&mt('Text').'</label></span></p>';
                    333:         }
                    334:     }
                    335:     $display .= '<p>';
                    336:     if ($context eq 'imsexport') {
                    337:         $display .= 
                    338:            '<input type="hidden" name="finishexport" value="1" />'.
                    339:            '<input type="submit" name="exportcourse" value="'.
                    340:            &mt('Export').'" />';
                    341:     } elsif ($context eq 'examblock') {
                    342:         $display .=
                    343:             '<input type="submit" name="resourceblocks" value="'.
1.4     ! bisitz    344:             &mt('Copy Choices to Main Window').'" />';
1.1       raeburn   345:     }
                    346:     $display .= '</p></form>';
                    347:     my $numcount = $count + $boards + $startcount;
                    348:     my $scripttag = 
                    349:         &respicker_javascript($startcount,$numcount,$context,$formname,\%children,
                    350:                               \%hierarchy,\@checked_maps);
                    351:     my ($title,$crumbs,$args);
                    352:     if ($context eq 'imsexport') {
                    353:         $title = 'Export '.$crstype.' to IMS Package';
                    354:     } elsif ($context eq 'examblock') {
                    355:         $title = 'Resources with Access blocked';
                    356:         $args = {'only_body'      => 1,
                    357:                  'add_entries' => { onload => 'javascript:recurseFolders();' }, 
                    358:                 };
                    359:     }
1.3       raeburn   360:     $output = &Apache::loncommon::start_page($title,$scripttag,$args);
1.1       raeburn   361:     if ($context eq 'imsexport') {
1.2       raeburn   362:         $output .= &Apache::lonhtmlcommon::breadcrumbs('IMS Export').
                    363:                    &Apache::londocs::startContentScreen('tools');
1.1       raeburn   364:     }
                    365:     $output .= $display;
                    366:     if ($context eq 'examblock') {
                    367:         $output .= &Apache::loncommon::end_page();
1.2       raeburn   368:     } elsif ($context eq 'imsexport') {
                    369:         $output .= &Apache::londocs::endContentScreen();
1.1       raeburn   370:     }
                    371:     return $output;
                    372: }
                    373: 
                    374: sub respicker_javascript {
                    375:     my ($startcount,$numitems,$context,$formname,$children,$hierarchy,
                    376:         $checked_maps) = @_;
                    377:     return unless ((ref($children) eq 'HASH') && (ref($hierarchy) eq 'HASH')
                    378:                    && (ref($checked_maps) eq 'ARRAY'));
                    379:     my $scripttag = <<"START";
                    380: <script type="text/javascript">
                    381: // <![CDATA[
                    382: function checkAll(field) {
                    383:     if (field.length > 0) {
                    384:         for (i = 0; i < field.length; i++) {
                    385:             field[i].checked = true ;
                    386:         }
                    387:     } else {
                    388:         field.checked = true
                    389:     }
                    390: }
                    391: 
                    392: function uncheckAll(field) {
                    393:     if (field.length > 0) {
                    394:         for (i = 0; i < field.length; i++) {
                    395:             field[i].checked = false;
                    396:         }
                    397:     } else {
                    398:         field.checked = false;
                    399:     }
                    400: }
                    401: 
                    402: function checkFolder(form,item) {
                    403:     if (form.elements[item].checked == true) {
                    404:         containerCheck(form,item);
                    405:     } else {
                    406:         containerUncheck(form,item);
                    407:     }
                    408: }
                    409: 
                    410: function checkResource(form,item) {
                    411:     if (form.elements[item].checked == false) {
                    412:         containerUncheck(form,item);
                    413:     }
                    414: }
                    415: 
                    416: numitems = $numitems;
                    417: var parents = new Array(numitems);
                    418: var nesting = new Array(numitems);
                    419: var initial = new Array();
                    420: for (var i=$startcount; i<numitems; i++) {
                    421:     parents[i] = new Array();
                    422:     nesting[i] = new Array();
                    423: }
                    424: 
                    425: START
                    426: 
                    427:     foreach my $container (sort { $a <=> $b } (keys(%{$children}))) {
                    428:         my @contents = split(/:/,$children->{$container});
                    429:         for (my $i=0; $i<@contents; $i ++) {
                    430:             $scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
                    431:         }
                    432:     }
                    433: 
                    434:     if ($context eq 'examblock') {
                    435:         foreach my $item (sort { $a <=> $b } (keys(%{$hierarchy}))) {
                    436:             $scripttag .= "nesting[$item] = new Array($hierarchy->{$item});\n";
                    437:         }
                    438:          
                    439:         my @sorted_maps = sort { $a <=> $b } (@{$checked_maps});
                    440:         for (my $i=0; $i<@sorted_maps; $i++) {
                    441:             $scripttag .= "initial[$i] = '$sorted_maps[$i]'\n";
                    442:         }
                    443:         $scripttag .= <<"EXTRA";
                    444: 
                    445: function recurseFolders() {
                    446:     if (initial.length > 0) {
                    447:         for (var i=0; i<initial.length; i++) {
                    448:             containerCheck(document.$formname,initial[i]);
                    449:         }
                    450:     }
                    451:     return;
                    452: }
                    453: 
                    454: EXTRA
                    455:     }
                    456: 
                    457:     $scripttag .= <<"END";
                    458: 
                    459: function containerCheck(form,item) {
                    460:     form.elements[item].checked = true;
                    461:     if(Object.prototype.toString.call(parents[item]) === '[object Array]') {
                    462:         if (parents[item].length > 0) {
                    463:             for (var j=0; j<parents[item].length; j++) {
                    464:                 containerCheck(form,parents[item][j]);
                    465:             }
                    466:         }
                    467:     }
                    468: }
                    469: 
                    470: function containerUncheck(form,item) {
                    471:     if(Object.prototype.toString.call(nesting[item]) === '[object Array]') {
                    472:         if (nesting[item].length > 0) {
                    473:             for (var i=0; i<nesting[item].length; i++) {
                    474:                 form.elements[nesting[item][i]].checked = false;
                    475:             }
                    476:         }
                    477:     }
                    478:     return;
                    479: }
                    480: 
                    481: END
                    482: 
                    483:     if ($context eq 'examblock') {
                    484:         $scripttag .= <<ENDEX;
                    485: function writeToOpener(maps,resources) {
                    486:     var checkedmaps = '';
                    487:     var checkedresources = '';
                    488:     for (var i=0; i<document.$formname.archive.length; i++) {
                    489:         if (document.$formname.archive[i].checked) {
                    490:             var isResource = 1;
                    491:             var include = 1;
                    492:             var elemnum = i+1+$startcount;
                    493:             if (Object.prototype.toString.call(parents[elemnum]) === '[object Array]') {
                    494:                 if (parents[elemnum].length > 0) {
                    495:                     isResource = 0;
                    496:                 }
                    497:             }
                    498:             if (isResource == 1) {
                    499:                 if (nesting[elemnum].length > 0) {
                    500:                     var lastelem = nesting[elemnum].length-1;
                    501:                     if (document.$formname.elements[nesting[elemnum][lastelem]].checked) {
                    502:                         include = 0;
                    503:                     }
                    504:                 }
                    505:             }
                    506:             if (include == 1) {
                    507:                 if (isResource == 1) {
                    508:                     checkedresources += document.$formname.archive[i].value+',';
                    509:                 } else {
                    510:                     checkedmaps += document.$formname.archive[i].value+',';
                    511:                 }
                    512:             }
                    513:         }
                    514:     }
                    515:     opener.document.getElementById(maps).value = checkedmaps;
                    516:     opener.document.getElementById(resources).value = checkedresources;
                    517:     window.close();
                    518:     return false;
                    519: }
                    520: 
                    521: ENDEX
                    522:     }
                    523: 
                    524:     $scripttag .= '
                    525: // ]]>
                    526: </script>
                    527: ';
                    528:     return $scripttag;
                    529: }
                    530: 
                    531: sub get_navmap_object {
                    532:     my ($crstype,$context) = @_;
                    533:     my $navmap = Apache::lonnavmaps::navmap->new();
                    534:     my $outcome;
                    535:     if (!defined($navmap)) {
                    536:         if ($context eq 'imsexport') {
                    537:             $outcome = &Apache::loncommon::start_page('Export '.$crstype.' to IMS Package').
                    538:                       '<h2>'.&mt('IMS Export Failed').'</h2>';
                    539:         } elsif ($context eq 'examblock') {
                    540:             $outcome = &Apache::loncommon::start_page('Selection of Resources for Blocking',
                    541:                                                        undef,{'only_body' => 1,}).
                    542:                       '<h2>'.&mt('Resource Display Failed').'</h2>';  
                    543:         } 
                    544:         $outcome .= '<div class="LC_error">';
                    545:         if ($crstype eq 'Community') {
                    546:             $outcome .= &mt('Unable to retrieve information about community contents');
                    547:         } else {
                    548:             $outcome .= &mt('Unable to retrieve information about course contents');
                    549:         }
                    550:         $outcome .= '</div>';
                    551:         if ($context eq 'imsexport') {
                    552:             $outcome .= '<a href="/adm/coursedocs">';
                    553:             if ($crstype eq 'Community') {
                    554:                 $outcome .= &mt('Return to Community Editor');
                    555:             } else {
                    556:                 $outcome .= &mt('Return to Course Editor');
                    557:             }
                    558:             $outcome .= '</a>';
                    559:             &logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
                    560:         } elsif ($context eq 'examblock') {
                    561:             $outcome .=  '<href="javascript:window.close();">'.&mt('Close window').'</a>';         
                    562:         }
                    563:         return (undef,$outcome);
                    564:     } else {
                    565:         return ($navmap);
                    566:     }
                    567: }
                    568: 
                    569: 1;

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