--- loncom/interface/londocs.pm 2014/10/24 00:25:12 1.484.2.56 +++ loncom/interface/londocs.pm 2016/10/31 20:48:30 1.484.2.66 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: londocs.pm,v 1.484.2.56 2014/10/24 00:25:12 raeburn Exp $ +# $Id: londocs.pm,v 1.484.2.66 2016/10/31 20:48:30 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); @@ -3446,6 +3480,7 @@ END $currgroups); my ($copylink,$cutlink,$removelink); my $skip_confirm = 0; + my $confirm_removal = 0; if ( $folder =~ /^supplemental/ || ($url =~ m{( /smppg$ |/syllabus$ @@ -3456,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 @@ -3568,7 +3608,7 @@ END } } - my ($editlink,$extresform); + my ($editlink,$extresform,$anchor); my $orig_url = $url; $orig_url=~s{http(:|:)//https(:|:)//}{https$2//}; $url=~s{^http(|s)(:|:)//}{/adm/wrapper/ext/}; @@ -3590,11 +3630,28 @@ END $url='/adm/wrapper'.$url; } if (&Apache::lonnet::symbverify($symb,$url)) { - $url.=(($url=~/\?/)?'&':'?').'symb='.&escape($symb); + my $shownsymb = $symb; + if ($isexternal) { + if ($url =~ /^([^#]+)#([^#]+)$/) { + $url = $1; + $anchor = $2; + if ($symb =~ m{^([^#]+)\Q#$anchor\E$}) { + $shownsymb = $1.&escape('#').$anchor; + } + } + } + $url.=(($url=~/\?/)?'&':'?').'symb='.&HTML::Entities::encode($shownsymb,'"<>&'); } else { $url=''; } } + } elsif ($supplementalflag) { + if ($isexternal) { + if ($url =~ /^([^#]+)#([^#]+)$/) { + $url = $1; + $anchor = $2; + } + } } my ($rand_pick_text,$rand_order_text); if ($isfolder || $ispage || $extension eq 'sequence' || $extension eq 'page') { @@ -3662,6 +3719,9 @@ $form_end; if ($isexternal && $orderidx) { $url .= '&idx='.$orderidx; } + if ($anchor ne '') { + $url .= '&anchor='.&HTML::Entities::encode($anchor,'"<>&'); + } } my ($tdalign,$tdwidth); if ($allowed) { @@ -3674,13 +3734,17 @@ $form_end; my ($cfile,$home,$switchserver,$forceedit,$forceview) = &Apache::lonnet::can_edit_resource($fileloc,$coursenum,$coursedom,$orig_url); if (($cfile ne '') && ($symb ne '' || $supplementalflag)) { + my $suppanchor; + if ($supplementalflag) { + $suppanchor = $anchor; + } my $jscall = &Apache::lonhtmlcommon::jump_to_editres($cfile,$home, $switchserver, $forceedit, undef,$symb, &escape($env{'form.folderpath'}), - $renametitle,'','',1); + $renametitle,'','',1,$suppanchor); if ($jscall) { $editlink = ''.&mt('Edit').' '."\n"; @@ -3700,7 +3764,15 @@ $form_end; if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) { $line.=''; } elsif ($url) { - $line.=&Apache::loncommon::modal_link($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes', + if ($anchor ne '') { + if ($supplementalflag) { + $anchor = '&anchor='.&HTML::Entities::encode($anchor,'"<>&'); + } else { + $anchor = '#'.&HTML::Entities::encode($anchor,'"<>&'); + } + } + $line.=&Apache::loncommon::modal_link($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes'. + (($anchor ne '')?$anchor:''), '',600,500); } else { $line.=''; @@ -3709,7 +3781,8 @@ $form_end; if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) { $line.=''.$title.''; } elsif ($url) { - $line.=&Apache::loncommon::modal_link($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes', + $line.=&Apache::loncommon::modal_link($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes'. + (($anchor ne '')?$anchor:''), $title,600,500); } else { $line.=$title.' '.$reinit.''; @@ -3859,9 +3932,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.'); @@ -4855,7 +4938,39 @@ sub handler { 'webctce4' => 'WebCT 4 Campus Edition', ); # ----------------------------------------------------------------------------- + # Calculate free quota space for a user or course. + my $quotatype = 'unofficial'; + if ($crstype eq 'Community') { + $quotatype = 'community'; + } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.coursecode'}) { + $quotatype = 'official'; + } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.textbook'}) { + $quotatype = 'textbook'; + } + my $disk_quota = &Apache::loncommon::get_user_quota($coursenum,$coursedom, + 'course',$quotatype); # expressed in MB + my $current_disk_usage = 0; + foreach my $subdir ('docs','supplemental') { + $current_disk_usage += &Apache::lonnet::diskusage($coursedom,$coursenum, + "userfiles/$subdir",1); # expressed in kB + } + my $free_space = 1024 * ((1024 * $disk_quota) - $current_disk_usage); + my $usage = $current_disk_usage/1024; # in MB + my $quota = $disk_quota; + my $percent; + if ($disk_quota == 0) { + $percent = 100.0; + } else { + $percent = 100*($current_disk_usage/$disk_quota); + } + $usage = sprintf("%.2f",$usage); + $quota = sprintf("%.2f",$quota); + $percent = sprintf("%.0f",$percent); + my $quotainfo = '

'.&mt('Currently using [_1] of the [_2] available.', + $percent.'%',$quota.' MB').'

'; + my $fileupload=(< FIUP @@ -5755,7 +5870,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', @@ -5772,16 +5887,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', @@ -5794,6 +5911,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; @@ -5813,8 +5931,20 @@ sub editing_js { my ($map,$id,$res)=&Apache::lonnet::decode_symb($caller); $res = &Apache::lonnet::clutter($res); if (&Apache::lonnet::is_on_map($res)) { - $backtourl = &HTML::Entities::encode(&Apache::lonnet::clutter($res),'<>&"').'?symb='. + my ($url,$anchor); + if ($res =~ /^([^#]+)#([^#]+)$/) { + $url = $1; + $anchor = $2; + if (($caller =~ m{^([^#]+)\Q#$anchor\E$})) { + $caller = $1.&escape('#').$anchor; + } + } + $backtourl = &HTML::Entities::encode(&Apache::lonnet::clutter($url),'<>&"').'?symb='. &HTML::Entities::encode($caller,'<>&"'); + if ($anchor ne '') { + $backtourl .= '#'.&HTML::Entities::encode($anchor,'<>&"'); + } + $backtourl = &Apache::loncommon::escape_single($backtourl); } else { $backtourl = '/adm/navmaps'; } @@ -5837,7 +5967,7 @@ sub editing_js { return <$lt{'more'}'; + document.getElementById('more'+caller).innerHTML = '  $js_lt{'more'}'; } else { document.getElementById('more'+caller).innerHTML = ''; } @@ -6400,10 +6544,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'); @@ -6445,6 +6589,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)) { @@ -6459,6 +6604,11 @@ function checkSubmits() { remwarnings ++; } } + if (document.getElementById('confirm_removal_'+remidxs[i])) { + if (document.getElementById('confirm_removal_'+remidxs[i]).value == 1) { + removalinfo ++; + } + } } } } @@ -6557,14 +6707,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; } } @@ -6580,12 +6735,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; @@ -6700,13 +6855,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";