--- loncom/interface/londocs.pm 2004/08/22 18:15:54 1.138
+++ loncom/interface/londocs.pm 2012/05/15 01:41:27 1.487
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Documents
#
-# $Id: londocs.pm,v 1.138 2004/08/22 18:15:54 raeburn Exp $
+# $Id: londocs.pm,v 1.487 2012/05/15 01:41:27 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -30,16 +30,21 @@ package Apache::londocs;
use strict;
use Apache::Constants qw(:common :http);
+use Apache::imsexport;
use Apache::lonnet;
use Apache::loncommon;
-use Apache::lonratedt;
-use Apache::lonratsrv;
+use Apache::lonhtmlcommon;
+use LONCAPA::map();
+use Apache::lonratedt();
use Apache::lonxml;
-use Apache::loncreatecourse;
+use Apache::lonclonecourse;
use Apache::lonnavmaps;
+use Apache::lonnavdisplay();
use HTML::Entities;
use GDBM_File;
use Apache::lonlocal;
+use Cwd;
+use LONCAPA qw(:DEFAULT :match);
my $iconpath;
@@ -50,691 +55,1221 @@ my %alreadyseen=();
my $hadchanges;
-# Available help topics
my %help=();
-# Mapread read maps into lonratedt::global arrays
-# @order and @resources, determines status
-# sets @order - pointer to resources in right order
-# sets @resources - array with the resources with correct idx
-#
sub mapread {
my ($coursenum,$coursedom,$map)=@_;
return
- &Apache::lonratedt::mapread('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
- $map);
+ &LONCAPA::map::mapread('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
+ $map);
}
sub storemap {
my ($coursenum,$coursedom,$map)=@_;
my ($outtext,$errtext)=
- &Apache::lonratedt::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
- $map,1);
+ &LONCAPA::map::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
+ $map,1);
if ($errtext) { return ($errtext,2); }
-
+
$hadchanges=1;
return ($errtext,0);
}
-# ----------------------------------------- Return hash with valid author names
+
sub authorhosts {
my %outhash=();
my $home=0;
my $other=0;
- foreach (keys %ENV) {
- if ($_=~/^user\.role\.(au|ca)\.(.+)$/) {
+ foreach my $key (keys(%env)) {
+ if ($key=~/^user\.role\.(au|ca)\.(.+)$/) {
my $role=$1;
my $realm=$2;
- my ($start,$end)=split(/\./,$ENV{$_});
+ my ($start,$end)=split(/\./,$env{$key});
if (($start) && ($start>time)) { next; }
if (($end) && (time>$end)) { next; }
- my $ca; my $cd;
+ my ($ca,$cd);
if ($1 eq 'au') {
- $ca=$ENV{'user.name'};
- $cd=$ENV{'user.domain'};
+ $ca=$env{'user.name'};
+ $cd=$env{'user.domain'};
} else {
- ($cd,$ca)=($realm=~/^\/(\w+)\/(\w+)$/);
+ ($cd,$ca)=($realm=~/^\/($match_domain)\/($match_username)$/);
}
my $allowed=0;
my $myhome=&Apache::lonnet::homeserver($ca,$cd);
my @ids=&Apache::lonnet::current_machine_ids();
- foreach my $id (@ids) { if ($id eq $myhome) { $allowed=1; } }
+ foreach my $id (@ids) {
+ if ($id eq $myhome) {
+ $allowed=1;
+ last;
+ }
+ }
if ($allowed) {
$home++;
- $outhash{'home_'.$ca.'@'.$cd}=1;
+ $outhash{'home_'.$ca.':'.$cd}=1;
} else {
- $outhash{'otherhome_'.$ca.'@'.$cd}=$myhome;
+ $outhash{'otherhome_'.$ca.':'.$cd}=$myhome;
$other++;
}
}
}
return ($home,$other,%outhash);
}
-# ------------------------------------------------------ Generate "dump" button
-sub dumpbutton {
- my ($home,$other,%outhash)=&authorhosts();
- if ($home+$other==0) { return ''; }
- my $output='
';
- if ($home) {
- return ' '.
- ' '.
- &Apache::loncommon::help_open_topic('Docs_Dump_Course_Docs');
- } else {
- return' '.
- &mt('Dump Course DOCS to Construction Space: available on other servers');
- }
+
+sub clean {
+ my ($title)=@_;
+ $title=~s/[^\w\/\!\$\%\^\*\-\_\=\+\;\:\,\\\|\`\~]+/\_/gs;
+ return $title;
}
-# -------------------------------------------------------- Actually dump course
+
sub dumpcourse {
- my $r=shift;
- $r->print('Dump DOCS '.
- &Apache::loncommon::bodytag('Dump Course DOCS to Construction Space').
- '');
+ '
');
}
+ $r->print(&endContentScreen());
}
-# ------------------------------------------------------ Generate "export" button
+sub group_import {
+ my ($coursenum, $coursedom, $folder, $container, $caller, @files) = @_;
-sub exportbutton {
- return ' '.
- ' '.
- &Apache::loncommon::help_open_topic('Docs_Export_Course_Docs');
+ while (@files) {
+ my ($name, $url, $residx) = @{ shift(@files) };
+ if (($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$})
+ && ($caller eq 'londocs')
+ && (!&Apache::lonnet::stat_file($url))) {
+
+ my $errtext = '';
+ my $fatal = 0;
+ my $newmapstr = ''."\n".
+ ' '."\n".
+ ' '."\n".
+ ' '."\n".
+ ' ';
+ $env{'form.output'}=$newmapstr;
+ my $result=&Apache::lonnet::finishuserfileupload($coursenum,$coursedom,
+ 'output',$1.$2);
+ if ($result != m|^/uploaded/|) {
+ $errtext.='Map not saved: A network error occurred when trying to save the new map. ';
+ $fatal = 2;
+ }
+ if ($fatal) {
+ return ($errtext,$fatal);
+ }
+ }
+ if ($url) {
+ if (!$residx
+ || defined($LONCAPA::map::zombies[$residx])) {
+ $residx = &LONCAPA::map::getresidx($url,$residx);
+ push(@LONCAPA::map::order, $residx);
+ }
+ my $ext = 'false';
+ if ($url=~m{^http://} || $url=~m{^https://}) { $ext = 'true'; }
+ $url = &LONCAPA::map::qtunescape($url);
+ $name = &LONCAPA::map::qtunescape($name);
+ $LONCAPA::map::resources[$residx] =
+ join(':', ($name, $url, $ext, 'normal', 'res'));
+ }
+ }
+ return &storemap($coursenum, $coursedom, $folder.'.'.$container);
}
-sub exportcourse {
- my $r=shift;
- my %discussiontime = &Apache::lonnet::dump('discussiontimes',
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
- my $numdisc = keys %discussiontime;
- my $navmap = Apache::lonnavmaps::navmap->new();
- my $it=$navmap->getIterator(undef,undef,undef,1,undef,undef);
- my $curRes;
+sub breadcrumbs {
+ my ($allowed,$crstype)=@_;
+ &Apache::lonhtmlcommon::clear_breadcrumbs();
+ my (@folders);
+ if ($env{'form.pagepath'}) {
+ @folders = split('&',$env{'form.pagepath'});
+ } else {
+ @folders=split('&',$env{'form.folderpath'});
+ }
+ my $folderpath;
+ my $cpinfo='';
+ my $plain='';
+ my $randompick=-1;
+ my $isencrypted=0;
+ my $ishidden=0;
+ my $is_random_order=0;
+ while (@folders) {
+ my $folder=shift(@folders);
+ my $foldername=shift(@folders);
+ if ($folderpath) {$folderpath.='&';}
+ $folderpath.=$folder.'&'.$foldername;
+ my $url;
+ if ($allowed) {
+ $url = '/adm/coursedocs?folderpath=';
+ } else {
+ $url = '/adm/supplemental?folderpath=';
+ }
+ $url .= &escape($folderpath);
+ my $name=&unescape($foldername);
+# randompick number, hidden, encrypted, random order, is appended with ":"s to the foldername
+ $name=~s/\:(\d*)\:(\w*)\:(\w*):(\d*)$//;
+ if ($1 ne '') {
+ $randompick=$1;
+ } else {
+ $randompick=-1;
+ }
+ if ($2) { $ishidden=1; }
+ if ($3) { $isencrypted=1; }
+ if ($4 ne '') { $is_random_order = 1; }
+ if ($folder eq 'supplemental') {
+ $name = &mt('Supplemental '.$crstype.' Content');
+ }
+ &Apache::lonhtmlcommon::add_breadcrumb(
+ {'href'=>$url.$cpinfo,
+ 'title'=>$name,
+ 'text'=>$name,
+ 'no_mt'=>1,
+ });
+ $plain.=$name.' > ';
+ }
+ $plain=~s/\>\;\s*$//;
+ return (&Apache::lonhtmlcommon::breadcrumbs(undef,undef,0,'nohelp',
+ undef, undef, 1 ),$randompick,$ishidden,
+ $isencrypted,$plain,$is_random_order);
+}
+
+sub log_docs {
+ return &Apache::lonnet::instructor_log('docslog',@_);
+}
+
+{
+ my @oldresources=();
+ my @oldorder=();
+ my $parmidx;
+ my %parmaction=();
+ my %parmvalue=();
+ my $changedflag;
+
+ sub snapshotbefore {
+ @oldresources=@LONCAPA::map::resources;
+ @oldorder=@LONCAPA::map::order;
+ $parmidx=undef;
+ %parmaction=();
+ %parmvalue=();
+ $changedflag=0;
+ }
+
+ sub remember_parms {
+ my ($idx,$parameter,$action,$value)=@_;
+ $parmidx=$idx;
+ $parmaction{$parameter}=$action;
+ $parmvalue{$parameter}=$value;
+ $changedflag=1;
+ }
+
+ sub log_differences {
+ my ($plain)=@_;
+ my %storehash=('folder' => $plain,
+ 'currentfolder' => $env{'form.folder'});
+ if ($parmidx) {
+ $storehash{'parameter_res'}=$oldresources[$parmidx];
+ foreach my $parm (keys(%parmaction)) {
+ $storehash{'parameter_action_'.$parm}=$parmaction{$parm};
+ $storehash{'parameter_value_'.$parm}=$parmvalue{$parm};
+ }
+ }
+ my $maxidx=$#oldresources;
+ if ($#LONCAPA::map::resources>$#oldresources) {
+ $maxidx=$#LONCAPA::map::resources;
+ }
+ for (my $idx=0; $idx<=$maxidx; $idx++) {
+ if ($LONCAPA::map::resources[$idx] ne $oldresources[$idx]) {
+ $storehash{'before_resources_'.$idx}=$oldresources[$idx];
+ $storehash{'after_resources_'.$idx}=$LONCAPA::map::resources[$idx];
+ $changedflag=1;
+ }
+ if ($LONCAPA::map::order[$idx] ne $oldorder[$idx]) {
+ $storehash{'before_order_res_'.$idx}=$oldresources[$oldorder[$idx]];
+ $storehash{'after_order_res_'.$idx}=$LONCAPA::map::resources[$LONCAPA::map::order[$idx]];
+ $changedflag=1;
+ }
+ }
+ $storehash{'maxidx'}=$maxidx;
+ if ($changedflag) { &log_docs(\%storehash); }
+ }
+}
- &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
- ['finishexport']);
- if ($ENV{'form.finishexport'}) {
- &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
- ['archive','discussion']);
-
- my @exportitems = ();
- if (defined($ENV{'form.archive'})) {
- if (ref($ENV{'form.archive'}) eq 'ARRAY') {
- @exportitems = @{$ENV{'form.archive'}};
- } else {
- $exportitems[0] = $ENV{'form.archive'};
+sub docs_change_log {
+ my ($r,$coursenum,$coursedom,$folder,$allowed,$crstype,$iconpath)=@_;
+ my $supplementalflag=($env{'form.folderpath'}=~/^supplemental/);
+ my $js = ''."\n";
+ $r->print(&Apache::loncommon::start_page('Content Change Log',$js));
+ $r->print(&Apache::lonhtmlcommon::breadcrumbs('Content Change Log'));
+ $r->print(&startContentScreen('docs'));
+ my %orderhash;
+ my $container='sequence';
+ my $pathitem;
+ if ($env{'form.pagepath'}) {
+ $container='page';
+ $pathitem = ' ';
+ } else {
+ my $folderpath=$env{'form.folderpath'};
+ if ($folderpath eq '') {
+ $folderpath = 'default&'.&escape(&mt('Main '.$crstype.' Documents'));
+ }
+ $pathitem = ' ';
+ }
+ my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container";
+ my $jumpto = $readfile;
+ $jumpto =~ s{^/}{};
+ my $tid = 1;
+ my ($breadcrumbtrail) = &breadcrumbs($allowed,$crstype);
+ $r->print($breadcrumbtrail.
+ &generate_edit_table($tid,\%orderhash,undef,$iconpath,$jumpto,
+ $readfile));
+ my %docslog=&Apache::lonnet::dump('nohist_docslog',
+ $env{'course.'.$env{'request.course.id'}.'.domain'},
+ $env{'course.'.$env{'request.course.id'}.'.num'});
+
+ if ((keys(%docslog))[0]=~/^error\:/) { undef(%docslog); }
+
+ my %saveable_parameters = ('show' => 'scalar',);
+ &Apache::loncommon::store_course_settings('docs_log',
+ \%saveable_parameters);
+ &Apache::loncommon::restore_course_settings('docs_log',
+ \%saveable_parameters);
+ if (!$env{'form.show'}) { $env{'form.show'}=10; }
+# FIXME: internationalization seems wrong here
+ my %lt=('hiddenresource' => 'Resources hidden',
+ 'encrypturl' => 'URL hidden',
+ 'randompick' => 'Randomly pick',
+ 'randomorder' => 'Randomly ordered',
+ 'set' => 'set to',
+ 'del' => 'deleted');
+ my $filter = &Apache::loncommon::display_filter('docslog')."\n".
+ $pathitem."\n".
+ ' '.
+ (' 'x2).' ';
+ $r->print(''.
+ '
'.&mt('Display of Content Changes').' '."\n".
+ &makedocslogform($filter,1).
+ ' ');
+ $r->print(&Apache::loncommon::start_data_table().&Apache::loncommon::start_data_table_header_row().
+ ' '.&mt('Time').' '.&mt('User').' '.&mt('Folder').' '.&mt('Before').' '.
+ &mt('After').' '.
+ &Apache::loncommon::end_data_table_header_row());
+ my $shown=0;
+ foreach my $id (sort { $docslog{$b}{'exe_time'}<=>$docslog{$a}{'exe_time'} } (keys(%docslog))) {
+ if ($env{'form.displayfilter'} eq 'currentfolder') {
+ if ($docslog{$id}{'logentry'}{'currentfolder'} ne $folder) { next; }
+ }
+ my @changes=keys(%{$docslog{$id}{'logentry'}});
+ if ($env{'form.displayfilter'} eq 'containing') {
+ my $wholeentry=$docslog{$id}{'exe_uname'}.':'.$docslog{$id}{'exe_udom'}.':'.
+ &Apache::loncommon::plainname($docslog{$id}{'exe_uname'},$docslog{$id}{'exe_udom'});
+ foreach my $key (@changes) {
+ $wholeentry.=':'.$docslog{$id}{'logentry'}{$key};
+ }
+ if ($wholeentry!~/\Q$env{'form.containingphrase'}\E/i) { next; }
+ }
+ my $count = 0;
+ my $time =
+ &Apache::lonlocal::locallocaltime($docslog{$id}{'exe_time'});
+ my $plainname =
+ &Apache::loncommon::plainname($docslog{$id}{'exe_uname'},
+ $docslog{$id}{'exe_udom'});
+ my $about_me_link =
+ &Apache::loncommon::aboutmewrapper($plainname,
+ $docslog{$id}{'exe_uname'},
+ $docslog{$id}{'exe_udom'});
+ my $send_msg_link='';
+ if ((($docslog{$id}{'exe_uname'} ne $env{'user.name'})
+ || ($docslog{$id}{'exe_udom'} ne $env{'user.domain'}))) {
+ $send_msg_link =' '.
+ &Apache::loncommon::messagewrapper(&mt('Send message'),
+ $docslog{$id}{'exe_uname'},
+ $docslog{$id}{'exe_udom'});
+ }
+ $r->print(&Apache::loncommon::start_data_table_row());
+ $r->print(''.$time.'
+ '.$about_me_link.
+ ''.$docslog{$id}{'exe_uname'}.
+ ':'.$docslog{$id}{'exe_udom'}.' '.
+ $send_msg_link.' '.
+ $docslog{$id}{'logentry'}{'folder'}.' ');
+# Before
+ for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
+ my $oldname=(split(/\:/,$docslog{$id}{'logentry'}{'before_resources_'.$idx}))[0];
+ my $newname=(split(/\:/,$docslog{$id}{'logentry'}{'after_resources_'.$idx}))[0];
+ if ($oldname ne $newname) {
+ $r->print(&LONCAPA::map::qtescape($oldname));
+ }
+ }
+ $r->print('');
+ for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
+ if ($docslog{$id}{'logentry'}{'before_order_res_'.$idx}) {
+ $r->print(''.&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'before_order_res_'.$idx}))[0]).' ');
+ }
+ }
+ $r->print(' ');
+# After
+ $r->print(' ');
+
+ for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
+ my $oldname=(split(/\:/,$docslog{$id}{'logentry'}{'before_resources_'.$idx}))[0];
+ my $newname=(split(/\:/,$docslog{$id}{'logentry'}{'after_resources_'.$idx}))[0];
+ if ($oldname ne '' && $oldname ne $newname) {
+ $r->print(&LONCAPA::map::qtescape($newname));
+ }
+ }
+ $r->print('');
+ for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
+ if ($docslog{$id}{'logentry'}{'after_order_res_'.$idx}) {
+ $r->print(''.&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'after_order_res_'.$idx}))[0]).' ');
+ }
+ }
+ $r->print(' ');
+ if ($docslog{$id}{'logentry'}{'parameter_res'}) {
+ $r->print(&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'parameter_res'}))[0]).':');
+ foreach my $parameter ('randompick','hiddenresource','encrypturl','randomorder') {
+ if ($docslog{$id}{'logentry'}{'parameter_action_'.$parameter}) {
+# FIXME: internationalization seems wrong here
+ $r->print(''.
+ &mt($lt{$parameter}.' '.$lt{$docslog{$id}{'logentry'}{'parameter_action_'.$parameter}}.' [_1]',
+ $docslog{$id}{'logentry'}{'parameter_value_'.$parameter})
+ .' ');
+ }
+ }
+ $r->print(' ');
+ }
+# End
+ $r->print(' '.&Apache::loncommon::end_data_table_row());
+ $shown++;
+ if (!($env{'form.show'} eq &mt('all')
+ || $shown<=$env{'form.show'})) { last; }
+ }
+ $r->print(&Apache::loncommon::end_data_table()."\n".
+ &makesimpleeditform($pathitem)."\n".
+ '');
+ $r->print(&endContentScreen());
+}
+
+sub update_paste_buffer {
+ my ($coursenum,$coursedom) = @_;
+
+ return if (!defined($env{'form.markcopy'}));
+ return if (!defined($env{'form.copyfolder'}));
+ return if ($env{'form.markcopy'} < 0);
+
+ my ($errtext,$fatal) = &mapread($coursenum,$coursedom,
+ $env{'form.copyfolder'});
+
+ return if ($fatal);
+
+# Mark for copying
+ my ($title,$url)=split(':',$LONCAPA::map::resources[$LONCAPA::map::order[$env{'form.markcopy'}]]);
+ if (&is_supplemental_title($title)) {
+ &Apache::lonnet::appenv({'docs.markedcopy_supplemental' => $title});
+ ($title) = &parse_supplemental_title($title);
+ } elsif ($env{'docs.markedcopy_supplemental'}) {
+ &Apache::lonnet::delenv('docs.markedcopy_supplemental');
+ }
+ $url=~s{http(:|:)//https(:|:)//}{https$2//};
+
+ &Apache::lonnet::appenv({'docs.markedcopy_title' => $title,
+ 'docs.markedcopy_url' => $url});
+ delete($env{'form.markcopy'});
+}
+
+sub print_paste_buffer {
+ my ($r,$container) = @_;
+ return if (!defined($env{'docs.markedcopy_url'}));
+
+ $r->print(''
+ .''.&mt('Clipboard').' '
+ .' ');
+}
+
+sub do_paste_from_buffer {
+ my ($coursenum,$coursedom,$folder) = @_;
+
+ if (!$env{'form.pastemarked'}) {
+ return;
+ }
+
+# paste resource to end of list
+ my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url'});
+ my $title=&LONCAPA::map::qtescape($env{'docs.markedcopy_title'});
+# Maps need to be copied first
+ if (($url=~/\.(page|sequence)$/) && ($url=~/^\/uploaded\//)) {
+ $title=&mt('Copy of').' '.$title;
+ my $newid=$$.int(rand(100)).time;
+ my ($oldid,$ext) = ($url=~/^(.+)\.(\w+)$/);
+ if ($oldid =~ m{^(/uploaded/\Q$coursedom\E/\Q$coursenum\E/)(\D+)(\d+)$}) {
+ my $path = $1;
+ my $prefix = $2;
+ my $ancestor = $3;
+ if (length($ancestor) > 10) {
+ $ancestor = substr($ancestor,-10,10);
}
+ $oldid = $path.$prefix.$ancestor;
}
- my @discussions = ();
- if (defined($ENV{'form.discussion'})) {
- if (ref($ENV{'form.discussion'}) eq 'ARRAY') {
- @discussions = $ENV{'form.discussion'};
+ my $counter = 0;
+ my $newurl=$oldid.$newid.'.'.$ext;
+ my $is_unique = &uniqueness_check($newurl);
+ while (!$is_unique && $counter < 100) {
+ $counter ++;
+ $newid ++;
+ $newurl = $oldid.$newid;
+ $is_unique = &uniqueness_check($newurl);
+ }
+ if (!$is_unique) {
+ if ($url=~/\.page$/) {
+ return &mt('Paste failed: an error occurred creating a unique URL for the composite page');
} else {
- $discussions[0] = $ENV{'form.discussion'};
+ return &mt('Paste failed: an error occurred creating a unique URL for the folder');
}
}
- my $curRes;
- my $count;
- my %symbs;
- my $display;
- while ($curRes = $it->next()) {
- if (ref($curRes)) {
- $count ++;
- $symbs{$count} = $curRes->symb();
- if (grep/^$count$/,@exportitems) {
- $display.= 'Export content item '.$curRes->title()." \n";
- }
- if (grep/^$count$/,@discussions) {
- $display.= 'Export discussion posts '.$curRes->title()." \n";
- }
+ my $storefn=$newurl;
+ $storefn=~s{^/\w+/$match_domain/$match_username/}{};
+ my $paste_map_result =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn,
+ &Apache::lonnet::getfile($url));
+ if ($paste_map_result eq '/adm/notfound.html') {
+ if ($url=~/\.page$/) {
+ return &mt('Paste failed: an error occurred saving the composite page');
+ } else {
+ return &mt('Paste failed: an error occurred saving the folder');
}
}
-
- $r->print('Export Course '.
- &Apache::loncommon::bodytag('Export course to IMS or SCORM content package'
-));
-
- my $exportfile;
- $r->print($display);
- $r->print('');
- } else {
- my $display;
- $display = '