--- loncom/interface/londocs.pm 2014/03/18 02:37:52 1.484.2.51 +++ loncom/interface/londocs.pm 2016/08/06 20:00:29 1.484.2.63 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: londocs.pm,v 1.484.2.51 2014/03/18 02:37:52 raeburn Exp $ +# $Id: londocs.pm,v 1.484.2.63 2016/08/06 20:00:29 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -652,7 +652,7 @@ sub group_import { } else { $fname =~ s/\W/_/g; } - if (length($fname > 15)) { + if (length($fname) > 15) { $fname = substr($fname,0,14); } my $initialtext = &mt('Replace with your own content.'); @@ -977,7 +977,7 @@ sub docs_change_log { sub update_paste_buffer { my ($coursenum,$coursedom,$folder) = @_; - my (@possibles,%removals,%cuts); + my (@possibles,%removals,%cuts,$output); if ($env{'form.multiremove'}) { $env{'form.multiremove'} =~ s/,$//; map { $removals{$_} = 1; } split(/,/,$env{'form.multiremove'}); @@ -1045,10 +1045,12 @@ sub update_paste_buffer { 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 ($suffix ne '') { + push(@newpaste,$suffix); + } else { + if ($locknotfreed) { + return $locknotfreed; + } } if (&is_supplemental_title($title)) { &Apache::lonnet::appenv({'docs.markedcopy_supplemental_'.$suffix => $title}); @@ -1082,13 +1084,17 @@ sub update_paste_buffer { } } } + if ($locknotfreed) { + $output = $locknotfreed; + last; + } } if (@newpaste) { $addtoenv{'docs.markedcopies'} = join(',',(@currpaste,@newpaste)); } &Apache::lonnet::appenv(\%addtoenv); delete($env{'form.markcopy'}); - return; + return $output; } sub recurse_uploaded_maps { @@ -1191,10 +1197,14 @@ sub print_paste_buffer { $icon = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL')); $icon .= '/navmap.folder.closed.gif'; } + my $title = $env{'docs.markedcopy_title_'.$suffix}; + if ($title eq '') { + ($title) = ($url =~ m{/([^/]+)$}); + } $buffer = ''. ': '. &Apache::loncommon::parse_supplemental_title( - &LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix})); + &LONCAPA::map::qtescape($title)); } $pasteitems .= '
'; my ($options,$onclick); @@ -1343,29 +1353,34 @@ sub supp_pasteable { } sub paste_popup_js { - my %lt = &Apache::lonlocal::texthash( + my %html_js_lt = &Apache::lonlocal::texthash( show => 'Show Options', hide => 'Hide Options', + ); + my %js_lt = &Apache::lonlocal::texthash( none => 'No items selected from clipboard.', ); + &html_escape(\%html_js_lt); + &js_escape(\%html_js_lt); + &js_escape(\%js_lt); return <<"END"; function showPasteOptions(suffix) { document.getElementById('pasteoptions_'+suffix).style.display='block'; - document.getElementById('pasteoptionstext_'+suffix).innerHTML = '    $lt{'hide'}'; + document.getElementById('pasteoptionstext_'+suffix).innerHTML = '    $html_js_lt{'hide'}'; return; } function hidePasteOptions(suffix) { document.getElementById('pasteoptions_'+suffix).style.display='none'; - document.getElementById('pasteoptionstext_'+suffix).innerHTML ='    $lt{'show'}'; + document.getElementById('pasteoptionstext_'+suffix).innerHTML ='    $html_js_lt{'show'}'; return; } function showOptions(caller,suffix) { if (document.getElementById('pasteoptionstext_'+suffix)) { if (caller.checked) { - document.getElementById('pasteoptionstext_'+suffix).innerHTML ='    $lt{'show'}'; + document.getElementById('pasteoptionstext_'+suffix).innerHTML ='    $html_js_lt{'show'}'; } else { document.getElementById('pasteoptionstext_'+suffix).innerHTML =''; } @@ -1394,7 +1409,7 @@ function validateClipboard() { if (numchk > 0) { return true; } else { - alert("$lt{'none'}"); + alert("$js_lt{'none'}"); return false; } } @@ -2603,26 +2618,45 @@ sub update_parameter { } return $haschanges; } else { - return 0 if ($env{'form.changeparms'} !~ /^($valid_parameters_re)$/); + my $haschanges = 0; + return $haschanges if ($env{'form.changeparms'} !~ /^($valid_parameters_re)$/); my $which = $env{'form.changeparms'}; my $idx = $env{'form.setparms'}; + my $oldvalue = 0; + my $newvalue = 0; + my $current = (&LONCAPA::map::getparameter($idx,'parameter_'.$which))[0]; + if ($which eq 'randompick') { + if ($current =~ /^(\d+)$/) { + $oldvalue = $1; + } + } elsif ($current =~ /^yes$/i) { + $oldvalue = 1; + } if ($env{'form.'.$which.'_'.$idx}) { - my $value = ($which eq 'randompick') ? $env{'form.rpicknum_'.$idx} - : 'yes'; - &LONCAPA::map::storeparameter($idx, 'parameter_'.$which, $value, - $parameter_type{$which}); - &remember_parms($idx,$which,'set',$value); - } else { - &LONCAPA::map::delparameter($idx,'parameter_'.$which); - - &remember_parms($idx,$which,'del'); + $newvalue = ($which eq 'randompick') ? $env{'form.rpicknum_'.$idx} + : 1; } - return 1; + if ($oldvalue ne $newvalue) { + $haschanges = 1; + if ($newvalue) { + my $storeval = 'yes'; + if ($which eq 'randompick') { + $storeval = $newvalue; + } + &LONCAPA::map::storeparameter($idx, 'parameter_'.$which, $storeval, + $parameter_type{$which}); + &remember_parms($idx,$which,'set',$storeval); + } else { + &LONCAPA::map::delparameter($idx,'parameter_'.$which); + &remember_parms($idx,$which,'del'); + } + } + return $haschanges; } + return; } - sub handle_edit_cmd { my ($coursenum,$coursedom) =@_; if ($env{'form.cmd'} eq '') { @@ -2714,7 +2748,7 @@ sub editor { &snapshotbefore(); if (&update_parameter()) { - ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container); + ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container,1); return $errtext if ($fatal); } @@ -2776,9 +2810,9 @@ sub editor { $r->print($upload_output); # Rename, cut, copy or remove a single resource - if (&handle_edit_cmd()) { + if (&handle_edit_cmd($coursenum,$coursedom)) { my $contentchg; - if ($env{'form.cmd'} =~ m{^(del|cut)_}) { + if ($env{'form.cmd'} =~ m{^(remove|cut)_}) { $contentchg = 1; } ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container,$contentchg); @@ -2810,7 +2844,7 @@ sub editor { my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]); $name=&LONCAPA::map::qtescape($name); $url=&LONCAPA::map::qtescape($url); - next unless ($name && $url); + next unless $url; my %denied = &action_restrictions($coursenum,$coursedom,$url, $env{'form.folderpath'},\%curr_groups); @@ -3345,7 +3379,7 @@ sub is_supplemental_title { sub entryline { my ($index,$title,$url,$folder,$allowed,$residx,$coursenum,$coursedom, $crstype,$pathitem,$supplementalflag,$container,$filtersref,$currgroups)=@_; - my ($foldertitle,$renametitle); + my ($foldertitle,$renametitle,$oldtitle); if (&is_supplemental_title($title)) { ($title,$foldertitle,$renametitle) = &Apache::loncommon::parse_supplemental_title($title); } else { @@ -3358,8 +3392,10 @@ sub entryline { $renametitle=~s/\\/\\\\/g; $renametitle=~s/\"\;/\\\"/g; - $renametitle=~s/\'\;/\\\'/g; + $renametitle=~s/"/%22/g; $renametitle=~s/ /%20/g; + $oldtitle = $renametitle; + $renametitle=~s/\'\;/\\\'/g; my $line=&Apache::loncommon::start_data_table_row(); my ($form_start,$form_end,$form_common,$form_param); # Edit commands @@ -3444,6 +3480,7 @@ END $currgroups); my ($copylink,$cutlink,$removelink); my $skip_confirm = 0; + my $confirm_removal = 0; if ( $folder =~ /^supplemental/ || ($url =~ m{( /smppg$ |/syllabus$ @@ -3454,6 +3491,10 @@ END || $isexternal) { $skip_confirm = 1; } + if (($url=~m|/+uploaded/\Q$coursedom\E/\Q$coursenum\E/|) && + ($url!~/$LONCAPA::assess_page_seq_re/)) { + $confirm_removal = 1; + } if ($denied{'copy'}) { $copylink=(< $form_common + $lt{'rm'} $form_end ENDREM @@ -3509,7 +3551,7 @@ ENDREM } } $renamelink=(<$lt{'rn'} +$lt{'rn'} ENDREN $line.=(< @@ -3824,6 +3866,7 @@ sub new_timebased_suffix { if ($type eq 'paste') { $prefix = $type; $namespace = 'courseeditor'; + $idtype = 'addcode'; } elsif ($type eq 'map') { $prefix = 'docs'; if ($area eq 'supplemental') { @@ -3835,9 +3878,8 @@ sub new_timebased_suffix { $prefix = $type; $namespace = 'templated'; } - $idtype = 'concat'; my ($suffix,$freedlock,$error) = - &Apache::lonnet::get_timebased_id($prefix,'num',$namespace,$dom,$num); + &Apache::lonnet::get_timebased_id($prefix,'num',$namespace,$dom,$num,$idtype); if (!$suffix) { if ($type eq 'paste') { $errtext = &mt('Failed to acquire a unique timestamp-based suffix when adding to the paste buffer.'); @@ -3857,9 +3899,19 @@ sub new_timebased_suffix { '
'. &mt('There was a problem removing a lockfile.').' '; if ($type eq 'paste') { - &mt('This will prevent use of the paste buffer until th next log-in.'); + if ($freedlock eq 'nolock') { + $locknotfreed = + '
'. + &mt('A lockfile was not released when you added content to the clipboard earlier in this session.').' '. + + &mt('As a result addition of items to the clipboard will be unavailable until your next log-in.'); + } else { + $locknotfreed .= + &mt('This will prevent addition of items to the clipboard until your next log-in.'); + } } elsif ($type eq 'map') { - &mt('This will prevent creation of additional folders or composite pages in this course.'); + $locknotfreed .= + &mt('This will prevent creation of additional folders or composite pages in this course.'); } elsif ($type eq 'smppg') { $locknotfreed .= &mt('This will prevent creation of additional simple pages in this course.'); @@ -4504,12 +4556,8 @@ sub handler { $allowed = &Apache::lonnet::allowed('mdc',$env{'request.course.id'}); } - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['chooseserver', - 'inhibitmenu']); - if ($allowed && $env{'form.chooseserver'}) { - &choose_dump_server($r); - return OK; - } elsif ($allowed && $env{'form.verify'}) { + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['inhibitmenu']); + if ($allowed && $env{'form.verify'}) { &init_breadcrumbs('verify','Verify Content','Docs_Verify_Content'); &verifycontent($r); } elsif ($allowed && $env{'form.listsymbs'}) { @@ -5462,7 +5510,7 @@ sub decompression_info { my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'}; my $container='sequence'; my ($pathitem,$hiddenelem); - my @hiddens = ('newidx','comment','position','folderpath'); + my @hiddens = ('newidx','comment','position','folderpath','archiveurl'); if ($env{'form.folderpath'} =~ /\:1$/) { $container='page'; } @@ -5470,7 +5518,7 @@ sub decompression_info { foreach my $item (@hiddens) { if ($env{'form.'.$item}) { $hiddenelem .= ''."\n"; + &HTML::Entities::encode($env{'form.'.$item},'<>&"').'" />'."\n"; } } return ($destination,$dir_root,$londocroot,$docudom,$docuname,$container, @@ -5527,25 +5575,34 @@ sub remove_archive { } else { $delwarning = &mt('An error occurred retrieving the contents of the current folder.'); } - $delwarning .= &mt('As a result the archive file has not been removed.'); + $delwarning .= ' '.&mt('As a result the archive file has not been removed.'); } else { my $currcmd = $env{'form.cmd'}; my $position = $env{'form.position'}; - if ($position > 0) { - $env{'form.cmd'} = 'remove_'.$position; - my ($title,$url,@rrest) = - split(/:/,$LONCAPA::map::resources[$LONCAPA::map::order[$position]]); - if (&handle_edit_cmd($docuname,$docudom)) { - ($errtext,$fatal) = &storemap($docuname,$docudom,$map,1); - if ($fatal) { - if ($container eq 'page') { - $delwarning = &mt('An error occurred updating the contents of the current page.'); + my $archiveidx = $position; + if ($position > 0) { + if (($env{'form.autoextract_camtasia'}) && (scalar(@LONCAPA::map::order) == 2)) { + $archiveidx = $position-1; + } + $env{'form.cmd'} = 'remove_'.$archiveidx; + my ($title,$url,@rrest) = + split(/:/,$LONCAPA::map::resources[$LONCAPA::map::order[$archiveidx]]); + if ($url eq $env{'form.archiveurl'}) { + if (&handle_edit_cmd($docuname,$docudom)) { + ($errtext,$fatal) = &storemap($docuname,$docudom,$map,1); + if ($fatal) { + if ($container eq 'page') { + $delwarning = &mt('An error occurred updating the contents of the current page.'); + } else { + $delwarning = &mt('An error occurred updating the contents of the current folder.'); + } } else { - $delwarning = &mt('An error occurred updating the contents of the current folder.'); + $delresult = &mt('Archive file removed.'); } - } else { - $delresult = &mt('Archive file removed.'); } + } else { + $delwarning .= &mt('Archive file had unexpected item number in folder.'). + ' '.&mt('As a result the archive file has not been removed.'); } } $env{'form.cmd'} = $currcmd; @@ -5748,7 +5805,7 @@ END sub editing_js { my ($udom,$uname,$supplementalflag) = @_; - my %lt = &Apache::lonlocal::texthash( + my %js_lt = &Apache::lonlocal::texthash( p_mnf => 'Name of New Folder', t_mnf => 'New Folder', p_mnp => 'Name of New Page', @@ -5765,16 +5822,18 @@ sub editing_js { p_mab_alrt2 => 'Please enter both user and domain in the format user:domain', p_chn => 'New Title', p_rmr1 => 'WARNING: Removing a resource makes associated grades and scores inaccessible!', - p_rmr2a => 'Remove[_99]', - p_rmr2b => '?[_99]', - p_rmr3a => 'Remove those [_2]', - p_rmr3b => 'items?[_2]', + p_rmr2a => 'Remove', + p_rmr2b => '?', + p_rmr3a => 'Remove those', + p_rmr3b => 'items?', + p_rmr4 => 'WARNING: Removing a resource uploaded to a course cannot be undone via "Undo Delete".', + p_rmr5 => 'Push "Cancel" and then use "Cut" instead if you might need to undo this change.', p_ctr1a => 'WARNING: Cutting a resource makes associated grades and scores inaccessible!', p_ctr1b => 'Grades remain inaccessible if resource is pasted into another folder.', - p_ctr2a => 'Cut[_98]', - p_ctr2b => '?[_98]', - p_ctr3a => 'Cut those[_2]', - p_ctr3b => 'items?[_2]', + p_ctr2a => 'Cut', + p_ctr2b => '?', + p_ctr3a => 'Cut those', + p_ctr3b => 'items?', rpck => 'Enter number to pick (e.g., 3)', imsfile => 'You must choose an IMS package for import', imscms => 'You must select which Course Management System was the source of the IMS package', @@ -5787,6 +5846,7 @@ sub editing_js { noac => 'No actions selected.', ); + &js_escape(\%js_lt); my $crstype = &Apache::loncommon::course_type(); my $docs_folderpath = &HTML::Entities::encode($env{'environment.internal.'.$env{'request.course.id'}.'.docs_folderpath.folderpath'},'<>&"'); my $main_container_page; @@ -5808,6 +5868,7 @@ sub editing_js { if (&Apache::lonnet::is_on_map($res)) { $backtourl = &HTML::Entities::encode(&Apache::lonnet::clutter($res),'<>&"').'?symb='. &HTML::Entities::encode($caller,'<>&"'); + $backtourl = &Apache::loncommon::escape_single($backtourl); } else { $backtourl = '/adm/navmaps'; } @@ -5830,7 +5891,7 @@ sub editing_js { return <$lt{'more'}'; + document.getElementById('more'+caller).innerHTML = '  $js_lt{'more'}'; } else { document.getElementById('more'+caller).innerHTML = ''; } @@ -6393,10 +6468,10 @@ function togglePick(caller,value) { function toggleCheckUncheck(caller,more) { if (more == 1) { - document.getElementById('more'+caller).innerHTML = '  $lt{'less'}'; + document.getElementById('more'+caller).innerHTML = '  $js_lt{'less'}'; document.getElementById('allfields'+caller).style.display='block'; } else { - document.getElementById('more'+caller).innerHTML = '  $lt{'more'}'; + document.getElementById('more'+caller).innerHTML = '  $js_lt{'more'}'; document.getElementById('allfields'+caller).style.display='none'; } resize_scrollbox('contentscroll','1','1'); @@ -6438,6 +6513,7 @@ function checkSubmits() { var doactions = multiActions(); var cutwarnings = 0; var remwarnings = 0; + var removalinfo = 0; if (doactions == 1) { var remidxlist = document.cumulativeactions.allremoveidx.value; if ((remidxlist != '') && (remidxlist != null)) { @@ -6452,6 +6528,11 @@ function checkSubmits() { remwarnings ++; } } + if (document.getElementById('confirm_removal_'+remidxs[i])) { + if (document.getElementById('confirm_removal_'+remidxs[i]).value == 1) { + removalinfo ++; + } + } } } } @@ -6550,14 +6631,19 @@ function checkSubmits() { } if (doactions == 1) { if (numchanges > 0) { - if ((cutwarnings > 0) || (remwarnings > 0)) { + if ((cutwarnings > 0) || (remwarnings > 0) || (removalinfo > 0)) { if (remwarnings > 0) { - if (!confirm('$lt{"p_rmr1"}\\n\\n$lt{"p_rmr3a"} '+remwarnings+' $lt{"p_rmr3b"}')) { + if (!confirm('$js_lt{"p_rmr1"}\\n\\n$js_lt{"p_rmr3a"} '+remwarnings+' $js_lt{"p_rmr3b"}')) { + return false; + } + } + if (removalinfo > 0) { + if (!confirm('$js_lt{"p_rmr4"}\\n$js_lt{"p_rmr5"}\\n\\n$js_lt{"p_rmr3a"} '+removalinfo+' $js_lt{"p_rmr3b"}')) { return false; } } if (cutwarnings > 0) { - if (!confirm('$lt{"p_ctr1a"}\\n$lt{"p_ctr1b"}\\n\\n$lt{"p_ctr3a"} '+cutwarnings+' $lt{"p_ctr3b"}')) { + if (!confirm('$js_lt{"p_ctr1a"}\\n$js_lt{"p_ctr1b"}\\n\\n$js_lt{"p_ctr3a"} '+cutwarnings+' $js_lt{"p_ctr3b"}')) { return false; } } @@ -6573,12 +6659,12 @@ function checkSubmits() { } } if ((dosettings == 1) && (doactions == 1)) { - alert("$lt{'noor'}"); + alert("$js_lt{'noor'}"); } else { if (dosettings == 1) { - alert("$lt{'noch'}"); + alert("$js_lt{'noch'}"); } else { - alert("$lt{'noac'}"); + alert("$js_lt{'noac'}"); } } return false; @@ -6693,13 +6779,19 @@ ENDINJECT sub dump_switchserver_js { my @hosts = @_; - my %lt = &Apache::lonlocal::texthash( + my %js_lt = &Apache::lonlocal::texthash( dump => 'Copying content to Authoring Space requires switching server.', swit => 'Switch server?', + ); + my %html_js_lt = &Apache::lonlocal::texthash( + swit => 'Switch server?', duco => 'Copying Content to Authoring Space', yone => 'You need to switch to a server housing an Authoring Space for which you are author or co-author.', chos => 'Choose server', ); + &js_escape(\%js_lt); + &html_escape(\%html_js_lt); + &js_escape(\%html_js_lt); my $role = $env{'request.role'}; my $js = <<"ENDSWJS";