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

1.1       raeburn     1: # The LearningOnline Network
                      2: #
1.2     ! raeburn     3: # $Id: loncourserespicker.pm,v 1.1 2012/03/31 12:02:21 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 $curRes;
                    227:     my $lastcontainer = $startcount;
                    228:     $display .= &Apache::loncommon::start_data_table()
                    229:                .&Apache::loncommon::start_data_table_header_row();
                    230:     if ($context eq 'imsexport') {
                    231:         $display .= '<th>'.&mt('Export content item?').'</th>';
                    232:         if ($numdisc > 0) {
                    233:             $display .= '<th>'.&mt('Export discussion posts?').'</th>';
                    234:         }
                    235:     } elsif ($context eq 'examblock') {
                    236:         $display .= '<th>'.&mt('Access blocked?').'</th>';
                    237:     }
                    238:     $display .= &Apache::loncommon::end_data_table_header_row();
                    239:     while ($curRes = $it->next()) {
                    240:         if (ref($curRes)) {
                    241:              $count ++;
                    242:         }
                    243:         if ($curRes == $it->BEGIN_MAP()) {
                    244:             $depth++;
                    245:             $parent{$depth} = $lastcontainer;
                    246:         }
                    247:         if ($curRes == $it->END_MAP()) {
                    248:             $depth--;
                    249:             $lastcontainer = $parent{$depth};
                    250:         }
                    251:         if (ref($curRes)) {
                    252:             my $symb = $curRes->symb();
                    253:             my $ressymb = $symb;
                    254:             if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
                    255:                 unless ($ressymb =~ m|adm/wrapper/adm|) {
                    256:                     $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
                    257:                 }
                    258:             }
                    259:             my $currelem = $count+$boards+$startcount;
                    260:             $display .= &Apache::loncommon::start_data_table_row().
                    261:                        '<td>'."\n".
                    262:                        '<input type="checkbox" name="archive" value="'.$count.'" ';
                    263:             if (($curRes->is_sequence()) || ($curRes->is_page())) {
                    264:                 $lastcontainer = $currelem;
                    265:                 $display .= 'onclick="javascript:checkFolder(this.form,'."'$currelem'".')" ';
                    266:                 my $mapurl = (&Apache::lonnet::decode_symb($symb))[2];
                    267:                 if ($currmaps{$mapurl}) {
                    268:                     $display .= 'checked="checked"';
                    269:                     push(@checked_maps,$currelem);
                    270:                 }
                    271:             } else {
                    272:                 if ($curRes->is_problem()) {
                    273:                     $numprobs ++;
                    274:                 }
                    275:                 $display .= 'onclick="javascript:checkResource(this.form,'."'$currelem'".')" ';
                    276:                 if ($currresources{$symb}) {
                    277:                     $display .= 'checked="checked"';
                    278:                 }
                    279:             }
                    280:             $display .= ' />'."\n";
                    281:             for (my $i=0; $i<$depth; $i++) {
                    282:                 $display .= "$whitespace\n";
                    283:             }
                    284:             my $icon = 'src="'.$location.'/unknown.gif" alt=""';
                    285:             if ($curRes->is_sequence()) {
                    286:                 $icon = 'src="'.$location.'/navmap.folder.open.gif" alt="'.&mt('"Folder').'"';
                    287:             } elsif ($curRes->is_page()) {
                    288:                 $icon = 'src="'.$location.'/navmap.page.open.gif" alt="'.&mt('Composite Page').'"';
                    289:             } elsif ($curRes->is_problem()) {
                    290:                 $icon = 'src="'.$location.'/problem.gif" alt="'.&mt('Problem').'"';
                    291:             } elsif ($curRes->is_task()) {
                    292:                 $icon = 'src="'.$location.'/task.gif" alt="'.&mt('Task').'"';
                    293:             } elsif ($curRes->src ne '') {
                    294:                 $icon = 'src="'.&Apache::loncommon::icon($curRes->src).'" alt=""';
                    295:             }
                    296:             $display .= '<img '.$icon.' />&nbsp;'."\n";
                    297:             $children{$parent{$depth}} .= $currelem.':';
                    298:             if ($context eq 'examblock') {
                    299:                 if ($parent{$depth} > 1) {
                    300:                     if ($hierarchy{$parent{$depth}}) {
                    301:                         $hierarchy{$currelem} = $hierarchy{$parent{$depth}}.",'$parent{$depth}'";
                    302:                     } else {
                    303:                         $hierarchy{$currelem} = "'$parent{$depth}'";
                    304:                     }
                    305:                 }
                    306:             }
                    307:             $display .= '&nbsp;'.$curRes->title().'</td>'."\n";
                    308: 
                    309:             if ($context eq 'imsexport') {
                    310: # Existing discussion posts?
                    311:                 if ($discussiontime{$ressymb} > 0) {
                    312:                     $boards ++;
                    313:                     $display .= '<td align="right">'
                    314:                                .'<input type="checkbox" name="discussion" value="'.$count.'" />'
                    315:                                .'</td>'."\n";
                    316:                 } elsif ($numdisc > 0) {
                    317:                     $display .= '<td>&nbsp;</td>'."\n";
                    318:                 }
                    319:             }
                    320:             $display .= &Apache::loncommon::end_data_table_row();
                    321:         }
                    322:     }
                    323:     $display .= &Apache::loncommon::end_data_table();
                    324:     if ($context eq 'imsexport') {
                    325:         if ($numprobs > 0) {
                    326:             $display .= '<p><span class="LC_nobreak">'.
                    327:                         &mt('Export format for LON-CAPA problems:').
                    328:                         '<label><input type="radio" name="format" value="xml" checked="checked" />'.
                    329:                         '&nbsp;'.&mt('XML').'</label>'.('&nbsp;' x3).
                    330:                         '<label><input type="radio" name="format" value="html" />'.
                    331:                         '&nbsp;'.&mt('HTML').'</label>'.('&nbsp;' x3).
                    332:                         '<label><input type="radio" name="format" value="plaintext" />'.
                    333:                         '&nbsp;'.&mt('Text').'</label></span></p>';
                    334:         }
                    335:     }
                    336:     $display .= '<p>';
                    337:     if ($context eq 'imsexport') {
                    338:         $display .= 
                    339:            '<input type="hidden" name="finishexport" value="1" />'.
                    340:            '<input type="submit" name="exportcourse" value="'.
                    341:            &mt('Export').'" />';
                    342:     } elsif ($context eq 'examblock') {
                    343:         $display .=
                    344:             '<input type="submit" name="resourceblocks" value="'.
                    345:             &mt('Copy Choices to Main Window ').'" />';
                    346:     }
                    347:     $display .= '</p></form>';
                    348:     my $numcount = $count + $boards + $startcount;
                    349:     my $scripttag = 
                    350:         &respicker_javascript($startcount,$numcount,$context,$formname,\%children,
                    351:                               \%hierarchy,\@checked_maps);
                    352:     my ($title,$crumbs,$args);
                    353:     if ($context eq 'imsexport') {
                    354:         $title = 'Export '.$crstype.' to IMS Package';
                    355:     } elsif ($context eq 'examblock') {
                    356:         $title = 'Resources with Access blocked';
                    357:         $args = {'only_body'      => 1,
                    358:                  'add_entries' => { onload => 'javascript:recurseFolders();' }, 
                    359:                 };
                    360:     }
                    361:     my $output = &Apache::loncommon::start_page($title,$scripttag,$args);
                    362:     if ($context eq 'imsexport') {
1.2     ! raeburn   363:         $output .= &Apache::lonhtmlcommon::breadcrumbs('IMS Export').
        !           364:                    &Apache::londocs::startContentScreen('tools');
1.1       raeburn   365:     }
                    366:     $output .= $display;
                    367:     if ($context eq 'examblock') {
                    368:         $output .= &Apache::loncommon::end_page();
1.2     ! raeburn   369:     } elsif ($context eq 'imsexport') {
        !           370:         $output .= &Apache::londocs::endContentScreen();
1.1       raeburn   371:     }
                    372:     return $output;
                    373: }
                    374: 
                    375: sub respicker_javascript {
                    376:     my ($startcount,$numitems,$context,$formname,$children,$hierarchy,
                    377:         $checked_maps) = @_;
                    378:     return unless ((ref($children) eq 'HASH') && (ref($hierarchy) eq 'HASH')
                    379:                    && (ref($checked_maps) eq 'ARRAY'));
                    380:     my $scripttag = <<"START";
                    381: <script type="text/javascript">
                    382: // <![CDATA[
                    383: function checkAll(field) {
                    384:     if (field.length > 0) {
                    385:         for (i = 0; i < field.length; i++) {
                    386:             field[i].checked = true ;
                    387:         }
                    388:     } else {
                    389:         field.checked = true
                    390:     }
                    391: }
                    392: 
                    393: function uncheckAll(field) {
                    394:     if (field.length > 0) {
                    395:         for (i = 0; i < field.length; i++) {
                    396:             field[i].checked = false;
                    397:         }
                    398:     } else {
                    399:         field.checked = false;
                    400:     }
                    401: }
                    402: 
                    403: function checkFolder(form,item) {
                    404:     if (form.elements[item].checked == true) {
                    405:         containerCheck(form,item);
                    406:     } else {
                    407:         containerUncheck(form,item);
                    408:     }
                    409: }
                    410: 
                    411: function checkResource(form,item) {
                    412:     if (form.elements[item].checked == false) {
                    413:         containerUncheck(form,item);
                    414:     }
                    415: }
                    416: 
                    417: numitems = $numitems;
                    418: var parents = new Array(numitems);
                    419: var nesting = new Array(numitems);
                    420: var initial = new Array();
                    421: for (var i=$startcount; i<numitems; i++) {
                    422:     parents[i] = new Array();
                    423:     nesting[i] = new Array();
                    424: }
                    425: 
                    426: START
                    427: 
                    428:     foreach my $container (sort { $a <=> $b } (keys(%{$children}))) {
                    429:         my @contents = split(/:/,$children->{$container});
                    430:         for (my $i=0; $i<@contents; $i ++) {
                    431:             $scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
                    432:         }
                    433:     }
                    434: 
                    435:     if ($context eq 'examblock') {
                    436:         foreach my $item (sort { $a <=> $b } (keys(%{$hierarchy}))) {
                    437:             $scripttag .= "nesting[$item] = new Array($hierarchy->{$item});\n";
                    438:         }
                    439:          
                    440:         my @sorted_maps = sort { $a <=> $b } (@{$checked_maps});
                    441:         for (my $i=0; $i<@sorted_maps; $i++) {
                    442:             $scripttag .= "initial[$i] = '$sorted_maps[$i]'\n";
                    443:         }
                    444:         $scripttag .= <<"EXTRA";
                    445: 
                    446: function recurseFolders() {
                    447:     if (initial.length > 0) {
                    448:         for (var i=0; i<initial.length; i++) {
                    449:             containerCheck(document.$formname,initial[i]);
                    450:         }
                    451:     }
                    452:     return;
                    453: }
                    454: 
                    455: EXTRA
                    456:     }
                    457: 
                    458:     $scripttag .= <<"END";
                    459: 
                    460: function containerCheck(form,item) {
                    461:     form.elements[item].checked = true;
                    462:     if(Object.prototype.toString.call(parents[item]) === '[object Array]') {
                    463:         if (parents[item].length > 0) {
                    464:             for (var j=0; j<parents[item].length; j++) {
                    465:                 containerCheck(form,parents[item][j]);
                    466:             }
                    467:         }
                    468:     }
                    469: }
                    470: 
                    471: function containerUncheck(form,item) {
                    472:     if(Object.prototype.toString.call(nesting[item]) === '[object Array]') {
                    473:         if (nesting[item].length > 0) {
                    474:             for (var i=0; i<nesting[item].length; i++) {
                    475:                 form.elements[nesting[item][i]].checked = false;
                    476:             }
                    477:         }
                    478:     }
                    479:     return;
                    480: }
                    481: 
                    482: END
                    483: 
                    484:     if ($context eq 'examblock') {
                    485:         $scripttag .= <<ENDEX;
                    486: function writeToOpener(maps,resources) {
                    487:     var checkedmaps = '';
                    488:     var checkedresources = '';
                    489:     for (var i=0; i<document.$formname.archive.length; i++) {
                    490:         if (document.$formname.archive[i].checked) {
                    491:             var isResource = 1;
                    492:             var include = 1;
                    493:             var elemnum = i+1+$startcount;
                    494:             if (Object.prototype.toString.call(parents[elemnum]) === '[object Array]') {
                    495:                 if (parents[elemnum].length > 0) {
                    496:                     isResource = 0;
                    497:                 }
                    498:             }
                    499:             if (isResource == 1) {
                    500:                 if (nesting[elemnum].length > 0) {
                    501:                     var lastelem = nesting[elemnum].length-1;
                    502:                     if (document.$formname.elements[nesting[elemnum][lastelem]].checked) {
                    503:                         include = 0;
                    504:                     }
                    505:                 }
                    506:             }
                    507:             if (include == 1) {
                    508:                 if (isResource == 1) {
                    509:                     checkedresources += document.$formname.archive[i].value+',';
                    510:                 } else {
                    511:                     checkedmaps += document.$formname.archive[i].value+',';
                    512:                 }
                    513:             }
                    514:         }
                    515:     }
                    516:     opener.document.getElementById(maps).value = checkedmaps;
                    517:     opener.document.getElementById(resources).value = checkedresources;
                    518:     window.close();
                    519:     return false;
                    520: }
                    521: 
                    522: ENDEX
                    523:     }
                    524: 
                    525:     $scripttag .= '
                    526: // ]]>
                    527: </script>
                    528: ';
                    529:     return $scripttag;
                    530: }
                    531: 
                    532: sub get_navmap_object {
                    533:     my ($crstype,$context) = @_;
                    534:     my $navmap = Apache::lonnavmaps::navmap->new();
                    535:     my $outcome;
                    536:     if (!defined($navmap)) {
                    537:         if ($context eq 'imsexport') {
                    538:             $outcome = &Apache::loncommon::start_page('Export '.$crstype.' to IMS Package').
                    539:                       '<h2>'.&mt('IMS Export Failed').'</h2>';
                    540:         } elsif ($context eq 'examblock') {
                    541:             $outcome = &Apache::loncommon::start_page('Selection of Resources for Blocking',
                    542:                                                        undef,{'only_body' => 1,}).
                    543:                       '<h2>'.&mt('Resource Display Failed').'</h2>';  
                    544:         } 
                    545:         $outcome .= '<div class="LC_error">';
                    546:         if ($crstype eq 'Community') {
                    547:             $outcome .= &mt('Unable to retrieve information about community contents');
                    548:         } else {
                    549:             $outcome .= &mt('Unable to retrieve information about course contents');
                    550:         }
                    551:         $outcome .= '</div>';
                    552:         if ($context eq 'imsexport') {
                    553:             $outcome .= '<a href="/adm/coursedocs">';
                    554:             if ($crstype eq 'Community') {
                    555:                 $outcome .= &mt('Return to Community Editor');
                    556:             } else {
                    557:                 $outcome .= &mt('Return to Course Editor');
                    558:             }
                    559:             $outcome .= '</a>';
                    560:             &logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
                    561:         } elsif ($context eq 'examblock') {
                    562:             $outcome .=  '<href="javascript:window.close();">'.&mt('Close window').'</a>';         
                    563:         }
                    564:         return (undef,$outcome);
                    565:     } else {
                    566:         return ($navmap);
                    567:     }
                    568: }
                    569: 
                    570: 1;

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