--- loncom/interface/londocs.pm 2004/09/02 15:26:40 1.140
+++ loncom/interface/londocs.pm 2013/09/23 17:35:07 1.565
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Documents
#
-# $Id: londocs.pm,v 1.140 2004/09/02 15:26:40 www Exp $
+# $Id: londocs.pm,v 1.565 2013/09/23 17:35:07 bisitz Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -30,16 +30,23 @@ 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 Apache::lonextresedit();
use HTML::Entities;
+use HTML::TokeParser;
use GDBM_File;
use Apache::lonlocal;
+use Cwd;
+use LONCAPA qw(:DEFAULT :match);
my $iconpath;
@@ -49,836 +56,3522 @@ my $hashtied;
my %alreadyseen=();
my $hadchanges;
+my $suppchanges;
-# 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 ($coursenum,$coursedom,$map,$contentchg)=@_;
+ my $report;
+ if (($contentchg) && ($map =~ /^default/)) {
+ $report = 1;
+ }
my ($outtext,$errtext)=
- &Apache::lonratedt::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
- $map,1);
+ &LONCAPA::map::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
+ $map,1,$report);
if ($errtext) { return ($errtext,2); }
-
- $hadchanges=1;
+
+ if ($map =~ /^default/) {
+ $hadchanges=1;
+ } else {
+ $suppchanges=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) = @_;
+ my ($donechk,$allmaps,%hierarchy,%titles,%addedmaps,%removefrommap,
+ %removeparam,$importuploaded,$fixuperrors);
+ $allmaps = {};
+ 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 (($caller eq 'londocs') &&
+ ($folder =~ /^default/)) {
+ if (($url =~ /\.(page|sequence)$/) && (!$donechk)) {
+ my $chome = &Apache::lonnet::homeserver($coursenum,$coursedom);
+ my $cid = $coursedom.'_'.$coursenum;
+ $allmaps =
+ &Apache::loncommon::allmaps_incourse($coursedom,$coursenum,
+ $chome,$cid);
+ $donechk = 1;
+ }
+ if ($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$}) {
+ &contained_map_check($url,$folder,\%removefrommap,\%removeparam,
+ \%addedmaps,\%hierarchy,\%titles,$allmaps);
+ $importuploaded = 1;
+ } elsif ($url =~ m{^/res/.+\.(page|sequence)$}) {
+ next if ($allmaps->{$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'; }
+ $name = &LONCAPA::map::qtunescape($name);
+ if ($name eq '') {
+ $name = &LONCAPA::map::qtunescape(&mt('Web Page'));
+ }
+ if ($url =~ m{^/uploaded/$coursedom/$coursenum/((?:docs|supplemental)/(?:default|\d+))/new\.html$}) {
+ my $filepath = $1;
+ my $fname = $name;
+ if ($fname =~ /^\W+$/) {
+ $fname = 'web';
+ } else {
+ $fname =~ s/\W/_/g;
+ }
+ if (length($fname > 15)) {
+ $fname = substr($fname,0,14);
+ }
+ my $initialtext = &mt('Replace with your own content.');
+ my $newhtml = <
+
+$name
+
+
+$initialtext
+
+
+END
+ $env{'form.output'}=$newhtml;
+ my $result =
+ &Apache::lonnet::finishuserfileupload($coursenum,$coursedom,
+ 'output',
+ "$filepath/$residx/$fname.html");
+ if ($result =~ m{^/uploaded/}) {
+ $url = $result;
+ if ($filepath =~ /^supplemental/) {
+ $name = time.'___&&&___'.$env{'user.name'}.'___&&&___'.
+ $env{'user.domain'}.'___&&&___'.$name;
+ }
+ } else {
+ return (&mt('Failed to save new web page.'),1);
+ }
+ }
+ $url = &LONCAPA::map::qtunescape($url);
+ $LONCAPA::map::resources[$residx] =
+ join(':', ($name, $url, $ext, 'normal', 'res'));
+ }
+ }
+ if ($importuploaded) {
+ my %import_errors;
+ my %updated = (
+ removefrommap => \%removefrommap,
+ removeparam => \%removeparam,
+ );
+ my ($result,$msgsarray,$lockerror) =
+ &apply_fixups($folder,1,$coursedom,$coursenum,\%import_errors,\%updated);
+ if (keys(%import_errors) > 0) {
+ $fixuperrors =
+ ''."\n".
+ &mt('The following files are either dependencies of a web page or references within a folder and/or composite page for which errors occurred during import:')."\n".
+ '
'."\n";
+ foreach my $key (sort(keys(%import_errors))) {
+ $fixuperrors .= ''.$key.' '."\n";
+ }
+ $fixuperrors .= ' '."\n";
+ }
+ if (ref($msgsarray) eq 'ARRAY') {
+ if (@{$msgsarray} > 0) {
+ $fixuperrors .= ''.
+ join(' ',@{$msgsarray}).
+ '
';
+ }
+ }
+ if ($lockerror) {
+ $fixuperrors .= ''.
+ $lockerror.
+ '
';
+ }
+ }
+ my ($errtext,$fatal) =
+ &storemap($coursenum, $coursedom, $folder.'.'.$container,1);
+ unless ($fatal) {
+ if ($folder =~ /^supplemental/) {
+ &Apache::lonnet::get_numsuppfiles($coursenum,$coursedom,1);
+ my ($errtext,$fatal) = &mapread($coursenum,$coursedom,
+ $folder.'.'.$container);
+ }
+ }
+ return ($errtext,$fatal,$fixuperrors);
+}
-sub exportbutton {
- return ' '.
- ' '.
- &Apache::loncommon::help_open_topic('Docs_Export_Course_Docs');
+sub log_docs {
+ return &Apache::lonnet::write_log('course','docslog',@_);
}
-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;
+{
+ 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;
+ }
- &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
- ['finishexport']);
- if ($ENV{'form.finishexport'}) {
- &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
- ['archive','discussion']);
+ sub remember_parms {
+ my ($idx,$parameter,$action,$value)=@_;
+ $parmidx=$idx;
+ $parmaction{$parameter}=$action;
+ $parmvalue{$parameter}=$value;
+ $changedflag=1;
+ }
- 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 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); }
+ }
+}
+
+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(($supplementalflag?'suppdocs':'docs')));
+ my %orderhash;
+ my $container='sequence';
+ my $pathitem;
+ if ($env{'form.folderpath'} =~ /\:1$/) {
+ $container='page';
+ }
+ my $folderpath=$env{'form.folderpath'};
+ if ($folderpath eq '') {
+ $folderpath = 'default&'.&escape(&mt('Main Content').':::::');
+ }
+ $pathitem = ' ';
+ my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container";
+ my $jumpto = $readfile;
+ $jumpto =~ s{^/}{};
+ my $tid = 1;
+ if ($supplementalflag) {
+ $tid = 2;
+ }
+ my ($breadcrumbtrail) =
+ &Apache::lonhtmlcommon::docs_breadcrumbs($allowed,$crstype,1);
+ $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'}.' ');
+ my $is_supp = 0;
+ if ($docslog{$id}{'logentry'}{'currentfolder'} =~ /^supplemental/) {
+ $is_supp = 1;
+ }
+# 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) {
+ my $shown = &LONCAPA::map::qtescape($oldname);
+ if ($is_supp) {
+ $shown = &Apache::loncommon::parse_supplemental_title($shown);
+ }
+ $r->print($shown);
+ }
+ }
+ $r->print('');
+ for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
+ if ($docslog{$id}{'logentry'}{'before_order_res_'.$idx}) {
+ my $shown = &LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'before_order_res_'.$idx}))[0]);
+ if ($is_supp) {
+ $shown = &Apache::loncommon::parse_supplemental_title($shown);
+ }
+ $r->print(''.$shown.' ');
+ }
+ }
+ $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) {
+ my $shown = &LONCAPA::map::qtescape($newname);
+ if ($is_supp) {
+ $shown = &Apache::loncommon::parse_supplemental_title(&LONCAPA::map::qtescape($newname));
+ }
+ $r->print($shown);
+ }
+ }
+ $r->print('');
+ for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
+ if ($docslog{$id}{'logentry'}{'after_order_res_'.$idx}) {
+ my $shown = &LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'after_order_res_'.$idx}))[0]);
+ if ($is_supp) {
+ $shown = &Apache::loncommon::parse_supplemental_title($shown);
+ }
+ $r->print(''.$shown.' ');
+ }
+ }
+ $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,$folder) = @_;
+ my (@possibles,%removals,%cuts);
+ if ($env{'form.multiremove'}) {
+ $env{'form.multiremove'} =~ s/,$//;
+ map { $removals{$_} = 1; } split(/,/,$env{'form.multiremove'});
+ }
+ if (($env{'form.multicopy'}) || ($env{'form.multicut'})) {
+ if ($env{'form.multicut'}) {
+ $env{'form.multicut'} =~ s/,$//;
+ foreach my $item (split(/,/,$env{'form.multicut'})) {
+ unless ($removals{$item}) {
+ $cuts{$item} = 1;
+ push(@possibles,$item.':cut');
+ }
}
}
- my @discussions = ();
- if (defined($ENV{'form.discussion'})) {
- if (ref($ENV{'form.discussion'}) eq 'ARRAY') {
- @discussions = $ENV{'form.discussion'};
+ if ($env{'form.multicopy'}) {
+ $env{'form.multicopy'} =~ s/,$//;
+ foreach my $item (split(/,/,$env{'form.multicopy'})) {
+ unless ($removals{$item} || $cuts{$item}) {
+ push(@possibles,$item.':copy');
+ }
+ }
+ }
+ } elsif ($env{'form.markcopy'}) {
+ @possibles = split(/,/,$env{'form.markcopy'});
+ }
+
+ return if (@possibles == 0);
+ return if (!defined($env{'form.copyfolder'}));
+
+ my ($errtext,$fatal) = &mapread($coursenum,$coursedom,
+ $env{'form.copyfolder'});
+ return if ($fatal);
+
+ my %curr_groups = &Apache::longroup::coursegroups();
+
+# Retrieve current paste buffer suffixes.
+ my @currpaste = split(/,/,$env{'docs.markedcopies'});
+ my (%pasteurls,@newpaste);
+
+# Construct identifiers for current contents of user's paste buffer
+ if (@currpaste) {
+ foreach my $suffix (@currpaste) {
+ my $cid = $env{'docs.markedcopy_crs_'.$suffix};
+ my $url = $env{'docs.markedcopy_url_'.$suffix};
+ if (($cid =~ /^$match_domain(?:_)$match_courseid$/) &&
+ ($url ne '')) {
+ $pasteurls{$cid.'_'.$url} = 1;
+ }
+ }
+ }
+
+# Mark items for copying (skip any items already in user's paste buffer)
+ my %addtoenv;
+
+ foreach my $item (@possibles) {
+ my ($orderidx,$cmd) = split(/:/,$item);
+ next if ($orderidx =~ /\D/);
+ next unless (($cmd eq 'cut') || ($cmd eq 'copy') || ($cmd eq 'remove'));
+ my ($title,$url)=split(':',$LONCAPA::map::resources[$orderidx]);
+ my %denied = &action_restrictions($coursenum,$coursedom,
+ &LONCAPA::map::qtescape($url),
+ $env{'form.folderpath'},\%curr_groups);
+ next if ($denied{'copy'});
+ $url=~s{http(:|:)//https(:|:)//}{https$2//};
+ next if (exists($pasteurls{$coursedom.'_'.$coursenum.'_'.$url}));
+ my ($suffix,$errortxt,$locknotfreed) =
+ &new_timebased_suffix($env{'user.domain'},$env{'user.name'},'paste');
+ push(@newpaste,$suffix);
+ if ($locknotfreed) {
+ return $locknotfreed;
+ last;
+ }
+ if (&is_supplemental_title($title)) {
+ &Apache::lonnet::appenv({'docs.markedcopy_supplemental_'.$suffix => $title});
+ ($title) = &Apache::loncommon::parse_supplemental_title($title);
+ }
+
+ $addtoenv{'docs.markedcopy_title_'.$suffix} = $title,
+ $addtoenv{'docs.markedcopy_url_'.$suffix} = $url,
+ $addtoenv{'docs.markedcopy_cmd_'.$suffix} = $cmd,
+ $addtoenv{'docs.markedcopy_crs_'.$suffix} = $env{'request.course.id'};
+
+ if ($url =~ m{^/uploaded/$match_domain/$match_courseid/(default|supplemental)_?(\d*)\.(page|sequence)$}) {
+ my $prefix = $1;
+ my $subdir =$2;
+ if ($subdir eq '') {
+ $subdir = $prefix;
+ }
+ my (%addedmaps,%removefrommap,%removeparam,%hierarchy,%titles,%allmaps);
+ &contained_map_check($url,$folder,\%removefrommap,\%removeparam,\%addedmaps,
+ \%hierarchy,\%titles,\%allmaps);
+ if (ref($hierarchy{$url}) eq 'HASH') {
+ my ($nested,$nestednames);
+ &recurse_uploaded_maps($url,$subdir,\%hierarchy,\%titles,\$nested,\$nestednames);
+ $nested =~ s/\&$//;
+ $nestednames =~ s/\Q___&&&___\E$//;
+ if ($nested ne '') {
+ $addtoenv{'docs.markedcopy_nested_'.$suffix} = $nested;
+ }
+ if ($nestednames ne '') {
+ $addtoenv{'docs.markedcopy_nestednames_'.$suffix} = $nestednames;
+ }
+ }
+ }
+ }
+ if (@newpaste) {
+ $addtoenv{'docs.markedcopies'} = join(',',(@currpaste,@newpaste));
+ }
+ &Apache::lonnet::appenv(\%addtoenv);
+ delete($env{'form.markcopy'});
+}
+
+sub recurse_uploaded_maps {
+ my ($url,$dir,$hierarchy,$titlesref,$nestref,$namesref) = @_;
+ if (ref($hierarchy->{$url}) eq 'HASH') {
+ my @maps = map { $hierarchy->{$url}{$_}; } sort { $a <=> $b } (keys(%{$hierarchy->{$url}}));
+ my @titles = map { $titlesref->{$url}{$_}; } sort { $a <=> $b } (keys(%{$titlesref->{$url}}));
+ my (@uploaded,@names,%shorter);
+ for (my $i=0; $i<@maps; $i++) {
+ my ($inner) = ($maps[$i] =~ m{^/uploaded/$match_domain/$match_courseid/(?:default|supplemental)_(\d+)\.(?:page|sequence)$});
+ if ($inner ne '') {
+ push(@uploaded,$inner);
+ push(@names,&escape($titles[$i]));
+ $shorter{$maps[$i]} = $inner;
+ }
+ }
+ $$nestref .= "$dir:".join(',',@uploaded).'&';
+ $$namesref .= "$dir:".(join(',',@names)).'___&&&___';
+ foreach my $map (@maps) {
+ if ($shorter{$map} ne '') {
+ &recurse_uploaded_maps($map,$shorter{$map},$hierarchy,$titlesref,$nestref,$namesref);
+ }
+ }
+ }
+ return;
+}
+
+sub print_paste_buffer {
+ my ($r,$container,$folder,$coursedom,$coursenum) = @_;
+ return if (!defined($env{'docs.markedcopies'}));
+
+ unless (($env{'form.pastemarked'}) || ($env{'form.clearmarked'})) {
+ return if ($env{'docs.markedcopies'} eq '');
+ }
+
+ my @currpaste = split(/,/,$env{'docs.markedcopies'});
+ my ($pasteitems,@pasteable);
+
+# Construct identifiers for current contents of user's paste buffer
+ foreach my $suffix (@currpaste) {
+ next if ($suffix =~ /\D/);
+ my $cid = $env{'docs.markedcopy_crs_'.$suffix};
+ my $url = $env{'docs.markedcopy_url_'.$suffix};
+ if (($cid =~ /^$match_domain\_$match_courseid$/) &&
+ ($url ne '')) {
+ my ($is_external,$othercourse,$fromsupp,$is_uploaded_map,$parent,
+ $canpaste,$nopaste,$othercrs,$areachange);
+ my $extension = (split(/\./,$env{'docs.markedcopy_url_'.$suffix}))[-1];
+ if ($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) {
+ $is_external = 1;
+ }
+ if ($folder =~ /^supplemental/) {
+ $canpaste = &supp_pasteable($env{'docs.markedcopy_url_'.$suffix});
+ unless ($canpaste) {
+ $nopaste = &mt('Paste into Supplemental Content unavailable.');
+ }
+ } else {
+ $canpaste = 1;
+ }
+ if ($canpaste) {
+ if ($url =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)$}) {
+ my $srcdom = $1;
+ my $srcnum = $2;
+ my $rem = $3;
+ if (($srcdom ne $coursedom) || ($srcnum ne $coursenum)) {
+ $othercourse = 1;
+ if ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) {
+ if ($canpaste) {
+ $othercrs = ' '.&mt('(from another course)');
+ }
+ } else {
+ $canpaste = 0;
+ $nopaste = &mt('Paste from another course unavailable.');
+ }
+ }
+ if ($rem =~ m{^(default|supplemental)_?(\d*)\.(?:page|sequence)$}) {
+ my $prefix = $1;
+ $parent = $2;
+ if ($folder !~ /^\Q$prefix\E/) {
+ $areachange = 1;
+ }
+ $is_uploaded_map = 1;
+ }
+ }
+ }
+ if ($canpaste) {
+ push(@pasteable,$suffix);
+ }
+ my $buffer;
+ if ($is_external) {
+ $buffer = &mt('External Resource').': '.
+ &LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix}).' ('.
+ &LONCAPA::map::qtescape($url).')';
+ } else {
+ my $icon = &Apache::loncommon::icon($extension);
+ if ($extension eq 'sequence' &&
+ $url =~ m{/default_\d+\.sequence$}x) {
+ $icon = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL'));
+ $icon .= '/navmap.folder.closed.gif';
+ }
+ $buffer = ' '.
+ ': '.
+ &Apache::loncommon::parse_supplemental_title(
+ &LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix}));
+ }
+ $pasteitems .= '';
+ my ($options,$onclick);
+ if (($canpaste) && (!$areachange) && (!$othercourse) &&
+ ($env{'docs.markedcopy_cmd_'.$suffix} eq 'cut')) {
+ if (($is_uploaded_map) ||
+ ($url =~ /(bulletinboard|smppg)$/) ||
+ ($url =~ m{^/uploaded/$coursedom/$coursenum/(?:docs|supplemental)/(.+)$})) {
+ $options = &paste_options($suffix,$is_uploaded_map,$parent);
+ $onclick= 'onclick="showOptions(this,'."'$suffix'".');" ';
+ }
+ }
+ $pasteitems .= ' '.$buffer.' ';
+ if ($nopaste) {
+ $pasteitems .= $nopaste;
} else {
- $discussions[0] = $ENV{'form.discussion'};
+ if ($othercrs) {
+ $pasteitems .= $othercrs;
+ }
+ if ($options) {
+ $pasteitems .= $options;
+ }
}
+ $pasteitems .= '
';
}
- 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";
- }
+ }
+ if ($pasteitems eq '') {
+ &Apache::lonnet::delenv('docs.markedcopies');
+ }
+ my ($pasteform,$form_start,$buttons,$form_end);
+ if ($pasteitems) {
+ $pasteitems .= '
';
+ $form_start = '';
+ } else {
+ $pasteitems = &mt('Clipboard is empty');
+ }
+ $r->print($form_start
+ .''
+ .''.&mt('Clipboard').(' ' x2).$buttons.' '
+ .$pasteitems
+ .' '
+ .$form_end);
+}
+
+sub paste_options {
+ my ($suffix,$is_uploaded_map,$parent) = @_;
+ my ($copytext,$movetext);
+ if ($is_uploaded_map) {
+ $copytext = &mt('Copy to new folder');
+ $movetext = &mt('Move old');
+ } elsif ($env{'docs.markedcopy_url_'.$suffix} =~ /bulletinboard$/) {
+ $copytext = &mt('Copy to new board');
+ $movetext = &mt('Move (not posts)');
+ } elsif ($env{'docs.markedcopy_url_'.$suffix} =~ /smppg$/) {
+ $copytext = &mt('Copy to new page');
+ $movetext = &mt('Move');
+ } else {
+ $copytext = &mt('Copy to new file');
+ $movetext = &mt('Move');
+ }
+ my $output = ' '.
+ ' '.
+ ''.(' 'x 4).
+ ''.
+ ' '.
+ $copytext.' '.(' 'x2).' '.
+ '
'.
+ ' '.
+ $movetext.' ';
+ if (($is_uploaded_map) && ($env{'docs.markedcopy_nested_'.$suffix})) {
+ $output .= '
'.&mt('Folder to paste contains sub-folders').
+ ' ';
+ my @pastemaps = split(/\&/,$env{'docs.markedcopy_nested_'.$suffix});
+ my @titles = split(/\Q___&&&___\E/,$env{'docs.markedcopy_nestednames_'.$suffix});
+ my $lastdir = $parent;
+ my %depths = (
+ $lastdir => 0,
+ );
+ my (%display,%deps);
+ for (my $i=0; $i<@pastemaps; $i++) {
+ ($lastdir,my $subfolderstr) = split(/\:/,$pastemaps[$i]);
+ my ($namedir,$esctitlestr) = split(/\:/,$titles[$i]);
+ my @subfolders = split(/,/,$subfolderstr);
+ $deps{$lastdir} = \@subfolders;
+ my @subfoldertitles = map { &unescape($_); } split(/,/,$esctitlestr);
+ my $depth = $depths{$lastdir} + 1;
+ my $offset = int($depth * 4);
+ my $indent = (' ' x $offset);
+ for (my $j=0; $j<@subfolders; $j++) {
+ $depths{$subfolders[$j]} = $depth;
+ $display{$subfolders[$j]} =
+ ''.$indent.$subfoldertitles[$j].' '.
+ ''.
+ ' '.&mt('Copy to new').' '.(' ' x2).
+ ''.
+ ' '.
+ &mt('Move old').' '.
+ ' ';
+ }
+ }
+ &recurse_print(\$output,$parent,\%deps,\%display);
+ $output .= '
';
+ }
+ $output .= '
';
+ return $output;
+}
+
+sub recurse_print {
+ my ($outputref,$dir,$deps,$display) = @_;
+ $$outputref .= $display->{$dir}."\n";
+ if (ref($deps->{$dir}) eq 'ARRAY') {
+ foreach my $subdir (@{$deps->{$dir}}) {
+ &recurse_print($outputref,$subdir,$deps,$display);
+ }
+ }
+}
+
+sub supp_pasteable {
+ my ($url) = @_;
+ if (($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//}) ||
+ (($url =~ /\.sequence$/) && ($url =~ m{^/uploaded/})) ||
+ ($url =~ m{^/uploaded/$match_domain/$match_courseid/(docs|supplemental)/(default|\d+)/\d+/}) ||
+ ($url =~ m{^/adm/$match_domain/$match_username/aboutme}) ||
+ ($url =~ m{^/public/$match_domain/$match_courseid/syllabus})) {
+ return 1;
+ }
+ return;
+}
+
+sub paste_popup_js {
+ my %lt = &Apache::lonlocal::texthash(
+ show => 'Show Options',
+ hide => 'Hide Options',
+ none => 'No items selected from clipboard.',
+ );
+ return <<"END";
+
+function showPasteOptions(suffix) {
+ document.getElementById('pasteoptions_'+suffix).style.display='block';
+ document.getElementById('pasteoptionstext_'+suffix).innerHTML = ' ';
+ return;
+}
+
+function hidePasteOptions(suffix) {
+ document.getElementById('pasteoptions_'+suffix).style.display='none';
+ document.getElementById('pasteoptionstext_'+suffix).innerHTML =' ';
+ return;
+}
+
+function showOptions(caller,suffix) {
+ if (document.getElementById('pasteoptionstext_'+suffix)) {
+ if (caller.checked) {
+ document.getElementById('pasteoptionstext_'+suffix).innerHTML =' ';
+ } else {
+ document.getElementById('pasteoptionstext_'+suffix).innerHTML ='';
+ }
+ if (document.getElementById('pasteoptions_'+suffix)) {
+ document.getElementById('pasteoptions_'+suffix).style.display='none';
+ }
+ }
+ return;
+}
+
+function validateClipboard() {
+ var numchk = 0;
+ if (document.pasteform.pasting.length > 1) {
+ for (var i=0; i 0) {
+ return true;
+ } else {
+ alert("$lt{'none'}");
+ return false;
+ }
+}
- $r->print('Export Course '.
- &Apache::loncommon::bodytag('Export course to IMS or SCORM content package'
-));
-
- my $exportfile;
- $r->print($display);
- $r->print('