[LON-CAPA-cvs] cvs: doc /loncapafiles loncapafiles.lpml loncom loncapa_apache.conf loncom/homework edit.pm loncom/interface loncommon.pm loncourseauthor.pm londocs.pm loncom/lonnet/perl lonnet.pm
raeburn
raeburn at source.lon-capa.org
Sat Dec 31 09:09:02 EST 2022
raeburn Sat Dec 31 14:09:02 2022 EDT
Added files:
/loncom/interface loncourseauthor.pm
Modified files:
/loncom/interface loncommon.pm londocs.pm
/loncom/homework edit.pm
/loncom/lonnet/perl lonnet.pm
/loncom loncapa_apache.conf
/doc/loncapafiles loncapafiles.lpml
Log:
- Use ajax to dynamically update drop-down lists of directories and files
available in course author space.
-------------- next part --------------
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1399 loncom/interface/loncommon.pm:1.1400
--- loncom/interface/loncommon.pm:1.1399 Thu Dec 1 01:24:53 2022
+++ loncom/interface/loncommon.pm Sat Dec 31 14:08:58 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1399 2022/12/01 01:24:53 raeburn Exp $
+# $Id: loncommon.pm,v 1.1400 2022/12/31 14:08:58 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1233,7 +1233,12 @@
$result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
}
$result .= "</select>\n";
- my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
+ my %select2;
+ if (ref($hashref->{$firstdefault}) eq 'HASH') {
+ if (ref($hashref->{$firstdefault}->{'select2'}) eq 'HASH') {
+ %select2 = %{$hashref->{$firstdefault}->{'select2'}};
+ }
+ }
$result .= $middletext;
$result .= "<select size=\"1\" name=\"$secondselectname\"";
if ($onchangesecond) {
@@ -1816,8 +1821,11 @@
save => 'Save page to make this permanent',
);
&js_escape(\%js_lt);
+ my $showfile_js = &show_crsfiles_js();
$browse_or_search = <<"END";
+ $showfile_js
+
function toggleChooser(form,element,titleid,only,search) {
var disp = 'none';
if (document.getElementById('chooser_'+element)) {
@@ -1832,22 +1840,54 @@
toggleResImport(form,element);
}
document.getElementById('chooser_'+element).style.display = disp;
+ var dirsel = '';
+ var filesel = '';
+ if (document.getElementById('chooser_'+element+'_crsres')) {
+ var currcrsres = document.getElementById('chooser_'+element+'_crsres').style.display;
+ if (currcrsres == 'none') {
+ dirsel = 'coursepath_'+element;
+ var filesel = 'coursefile_'+element;
+ var include;
+ if (document.getElementById('crsres_include_'+element)) {
+ include = document.getElementById('crsres_include_'+element).value;
+ }
+ populateCrsSelects(form,dirsel,filesel,1,include,1,0,1,1);
+ }
+ }
+ if (document.getElementById('chooser_'+element+'_upload')) {
+ var currcrsupload = document.getElementById('chooser_'+element+'_upload').style.display;
+ if (currcrsupload == 'none') {
+ dirsel = 'crsauthorpath_'+element;
+ filesel = '';
+ populateCrsSelects(form,dirsel,filesel,0,'',1,0,1,0);
+ }
+ }
}
}
- function toggleCrsFile(form,element,numdirs) {
+ function toggleCrsFile(form,element) {
if (document.getElementById('chooser_'+element+'_crsres')) {
var curr = document.getElementById('chooser_'+element+'_crsres').style.display;
if (curr == 'none') {
- if (numdirs) {
+ if (document.getElementById('coursepath_'+element)) {
+ var numdirs;
+ if (document.getElementById('coursepath_'+element).length) {
+ numdirs = document.getElementById('coursepath_'+element).length;
+ }
form.elements['coursepath_'+element].selectedIndex = 0;
if (numdirs > 1) {
- window['select1'+element+'_changed']();
+ var selelem = form.elements['coursefile_'+element];
+ var i, len = selelem.options.length -1;
+ if (len >=0) {
+ for (i = len; i >= 0; i--) {
+ selelem.remove(i);
+ }
+ selelem.options[0] = new Option('','');
+ }
}
}
- }
+ }
document.getElementById('chooser_'+element+'_crsres').style.display = 'block';
-
}
if (document.getElementById('chooser_'+element+'_upload')) {
document.getElementById('chooser_'+element+'_upload').style.display = 'none';
@@ -1858,20 +1898,20 @@
return;
}
- function toggleCrsUpload(form,element,numcrsdirs) {
+ function toggleCrsUpload(form,element) {
if (document.getElementById('chooser_'+element+'_crsres')) {
document.getElementById('chooser_'+element+'_crsres').style.display = 'none';
}
if (document.getElementById('chooser_'+element+'_upload')) {
var curr = document.getElementById('chooser_'+element+'_upload').style.display;
if (curr == 'none') {
- if (numcrsdirs) {
- form.elements['crsauthorpath_'+element].selectedIndex = 0;
- form.elements['newsubdir_'+element][0].checked = true;
- toggleNewsubdir(form,element);
+ form.elements['newsubdir_'+element][0].checked = true;
+ toggleNewsubdir(form,element);
+ document.getElementById('chooser_'+element+'_upload').style.display = 'block';
+ if (document.getElementById('uploadcrsres_'+element)) {
+ document.getElementById('uploadcrsres_'+element).value = '';
}
}
- document.getElementById('chooser_'+element+'_upload').style.display = 'block';
}
return;
}
@@ -1915,19 +1955,21 @@
var filename = form.elements['coursefile_'+element];
var path = directory.options[directory.selectedIndex].value;
var file = filename.options[filename.selectedIndex].value;
- form.elements[element].value = '$respath';
- if (path == '/') {
- form.elements[element].value += file;
- } else {
- form.elements[element].value += path+'/'+file;
- }
- unClean();
- if (document.getElementById('previewimg_'+element)) {
- document.getElementById('previewimg_'+element).src = form.elements[element].value;
- var newsrc = document.getElementById('previewimg_'+element).src;
- }
- if (document.getElementById('showimg_'+element)) {
- document.getElementById('showimg_'+element).innerHTML = '($js_lt{save})';
+ if (file != '') {
+ form.elements[element].value = '$respath';
+ if (path == '/') {
+ form.elements[element].value += file;
+ } else {
+ form.elements[element].value += path+'/'+file;
+ }
+ unClean();
+ if (document.getElementById('previewimg_'+element)) {
+ document.getElementById('previewimg_'+element).src = form.elements[element].value;
+ var newsrc = document.getElementById('previewimg_'+element).src;
+ }
+ if (document.getElementById('showimg_'+element)) {
+ document.getElementById('showimg_'+element).innerHTML = '($js_lt{save})';
+ }
}
toggleChooser(form,element);
return;
@@ -2216,111 +2258,168 @@
}
sub import_crsauthor_form {
- my ($form,$firstselectname,$secondselectname,$onchangefirst,$only,$suffix,$disabled) = @_;
+ my ($firstselectname,$secondselectname,$onchangefirst,$only,$suffix,$disabled) = @_;
return (0) unless ($env{'request.course.id'});
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $crshome = $env{'course.'.$env{'request.course.id'}.'.home'};
return (0) unless (($cnum ne '') && ($cdom ne ''));
- my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
my @ids=&Apache::lonnet::current_machine_ids();
- my ($output,$is_home,$relpath,%subdirs,%files,%selimport_menus);
+ my ($output,$is_home,$toppath,%subdirs,%files,%selimport_menus,$include,$exclude);
if (grep(/^\Q$crshome\E$/, at ids)) {
$is_home = 1;
}
- $relpath = "/priv/$cdom/$cnum";
- &Apache::lonnet::recursedirs($is_home,'priv',$londocroot,$relpath,'',\%subdirs,\%files);
+ $toppath = "/priv/$cdom/$cnum";
+ my $nonemptydir = 1;
+ my $js_only;
+ if ($only) {
+ map { $include->{$_} = 1; } split(/\s*,\s*/,$only);
+ $js_only = join(',',map { &js_escape($_); } sort(keys(%{$include})));
+ }
+ $exclude = &Apache::lonnet::priv_exclude();
+ &Apache::lonnet::recursedirs($is_home,1,$include,$exclude,1,$toppath,'',\%subdirs,\%files);
+ my $numdirs = scalar(keys(%files));
my %lt = &Apache::lonlocal::texthash (
fnam => 'Filename',
dire => 'Directory',
+ se => 'Select',
);
- my $numdirs = scalar(keys(%files));
- my (%possexts,$singledir, at singledirfiles);
- if ($only) {
- map { $possexts{$_} = 1; } split(/\s*,\s*/,$only);
- }
- my (%nonemptydirs,$possdirs);
- if ($numdirs > 1) {
- my @order;
- foreach my $key (sort { lc($a) cmp lc($b) } (keys(%files))) {
- if (ref($files{$key}) eq 'HASH') {
- my $shown = $key;
- if ($key eq '') {
- $shown = '/';
- }
- my @ordered = ();
- foreach my $file (sort { lc($a) cmp lc($b) } (keys(%{$files{$key}}))) {
- next if ($file =~ /\.rights$/);
- if ($only) {
- my ($ext) = ($file =~ /\.([^.]+)$/);
- unless ($possexts{lc($ext)}) {
- next;
- }
+ $output = $lt{'dire'}.
+ '<select id="'.$firstselectname.'" name="'.$firstselectname.'" '.
+ 'onchange="populateCrsSelects(this.form,'."'$firstselectname','$secondselectname',1,'$js_only',0,1,0,0".');">'.
+ '<option value="" selected="selected">'.$lt{'se'}.'</option>';
+ foreach my $key (sort { lc($a) cmp lc($b) } (keys(%files))) {
+ $output .= '<option value="'.$key.'">'.$key.'</option>'."\n";
+ }
+ $output .= '</select><br />'."\n".
+ $lt{'fnam'}.'<select id="'.$secondselectname.'" name="'.$secondselectname.'">'."\n".
+ '<option value="" selected="selected"></option>'."\n".
+ '</select>'."\n";
+ $output .= '<input type="hidden" id="crsres_include_'.$suffix.'" value="'.$only.'" />';
+ return ($numdirs,$output);
+}
+
+sub show_crsfiles_js {
+ my $excluderef = &Apache::lonnet::priv_exclude();
+ my $se = &js_escape(&mt('Select'));
+ my $exclude;
+ if (ref($excluderef) eq 'HASH') {
+ $exclude = join(',', map { &js_escape($_); } sort(keys(%{$excluderef})));
+ }
+ my $js = <<"END";
+
+
+ function populateCrsSelects (form,dirsel,filesel,exc,include,setdir,setfile,recurse,nonemptydir) {
+ var relpath = '';
+ if ((setfile) && (dirsel != null) && (dirsel != 'undefined') && (dirsel != '')) {
+ var currdir = form.elements[dirsel].options[form.elements[dirsel].selectedIndex].value;
+ if (currdir == '') {
+ if ((filesel != null) && (filesel != 'undefined') && (filesel != '')) {
+ selelem = form.elements[filesel];
+ var j, numfiles = selelem.options.length -1;
+ if (numfiles >=0) {
+ for (j = numfiles; j >= 0; j--) {
+ selelem.remove(j);
+ }
+ }
+ if (selelem.options.length == 0) {
+ selelem.options[selelem.options.length] = new Option('','');
+ selelem.selectedIndex = 0;
}
- $selimport_menus{$key}->{'select2'}->{$file} = $file;
- push(@ordered,$file);
- }
- if (@ordered) {
- push(@order,$key);
- $nonemptydirs{$key} = 1;
- $selimport_menus{$key}->{'text'} = $shown;
- $selimport_menus{$key}->{'default'} = '';
- $selimport_menus{$key}->{'select2'}->{''} = '';
- $selimport_menus{$key}->{'order'} = \@ordered;
}
+ return;
+ } else {
+ relpath = encodeURIComponent(form.elements[dirsel].options[form.elements[dirsel].selectedIndex].value);
}
}
- $possdirs = scalar(keys(%nonemptydirs));
- if ($possdirs > 1) {
- my @order = sort { lc($a) cmp lc($b) } (keys(%nonemptydirs));
- $output = $lt{'dire'}.
- &linked_select_forms($form,'<br />'.
- $lt{'fnam'},'',
- $firstselectname,$secondselectname,
- \%selimport_menus,\@order,
- $onchangefirst,'',$suffix).'<br />';
- } elsif ($possdirs == 1) {
- $singledir = (keys(%nonemptydirs))[0];
- if (ref($selimport_menus{$singledir}->{'order'}) eq 'ARRAY') {
- @singledirfiles = @{$selimport_menus{$singledir}->{'order'}};
- }
- delete($selimport_menus{$singledir});
- }
- } elsif ($numdirs == 1) {
- $singledir = (keys(%files))[0];
- foreach my $file (sort { lc($a) cmp lc($b) } (keys(%{$files{$singledir}}))) {
- if ($only) {
- my ($ext) = ($file =~ /\.([^.]+)$/);
- unless ($possexts{lc($ext)}) {
- next;
+ var http = new XMLHttpRequest();
+ var url = "/adm/courseauthor";
+ var crsrole = "$env{'request.role'}";
+ var exclude = '';
+ if (exc) {
+ exclude = '$exclude';
+ }
+ var params = "role=course&files=1&rec="+recurse+"&nonempty="+nonemptydir+"&exc="+exclude+"&inc="+include+"&path="+relpath;
+ http.open("POST", url, true);
+ http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+ http.onreadystatechange = function() {
+ if (http.readyState == 4 && http.status == 200) {
+ var data = JSON.parse(http.responseText);
+ var selelem;
+ if ((setdir) && (dirsel != null) && (dirsel != 'undefined') && (dirsel != '')) {
+ if (Array.isArray(data.dirs)) {
+ selelem = form.elements[dirsel];
+ var i, numdirs = selelem.options.length -1;
+ if (numdirs >=0) {
+ for (i = numdirs; i >= 0; i--) {
+ selelem.remove(i);
+ }
+ }
+ var len = data.dirs.length;
+ if (len) {
+ if (len > 1) {
+ selelem.options[selelem.options.length] = new Option('$se','');
+ }
+ }
+ if (len) {
+ var j;
+ for (j = 0; j < len; j++) {
+ selelem.options[selelem.options.length] = new Option(data.dirs[j],data.dirs[j]);
+ }
+ selelem.selectedIndex = 0;
+ }
+ if (!setfile) {
+ if ((filesel != null) && (filesel != 'undefined') && (filesel != '')) {
+ selelem = form.elements[filesel];
+ var j, numfiles = selelem.options.length -1;
+ if (numfiles >=0) {
+ for (j = numfiles; j >= 0; j--) {
+ selelem.remove(j);
+ }
+ }
+ if (selelem.options.length == 0) {
+ selelem.options[selelem.options.length] = new Option('','');
+ selelem.selectedIndex = 0;
+ }
+ }
+ }
+ }
+ }
+ if ((setfile) && (filesel != null) && (filesel != 'undefined') && (filesel != '')) {
+ selelem = form.elements[filesel];
+ var i, numfiles = selelem.options.length -1;
+ if (numfiles >=0) {
+ for (i = numfiles; i >= 0; i--) {
+ selelem.remove(i);
+ }
+ }
+ var x;
+ for (x in data.files) {
+ if (Array.isArray(data.files[x])) {
+ if (data.files[x].length > 1) {
+ selelem.options[selelem.options.length] = new Option('$se','');
+ }
+ var len = data.files[x].length;
+ if (len) {
+ var k;
+ for (k = 0; k < len; k++) {
+ selelem.options[selelem.options.length] = new Option(data.files[x][k],data.files[x][k]);
+ }
+ selelem.selectedIndex = 0;
+ }
+ }
+ }
+ if (selelem.options.length == 0) {
+ selelem.options[selelem.options.length] = new Option('','');
+ selelem.selectedIndex = 0;
+ }
}
- } else {
- next if ($file =~ /\.rights$/);
}
- push(@singledirfiles,$file);
- }
- if (@singledirfiles) {
- $possdirs = 1;
}
+ http.send(params);
}
- if (($possdirs == 1) && (@singledirfiles)) {
- my $showdir = $singledir;
- if ($singledir eq '') {
- $showdir = '/';
- }
- $output = $lt{'dire'}.
- '<select name="'.$firstselectname.'">'.
- '<option value="'.$singledir.'">'.$showdir.'</option>'."\n".
- '</select><br />'.
- $lt{'fnam'}.'<select name="'.$secondselectname.'">'."\n".
- '<option value="" selected="selected">'.$lt{'se'}.'</option>'."\n";
- foreach my $file (@singledirfiles) {
- $output .= '<option value="'.$file.'">'.$file.'</option>'."\n";
- }
- $output .= '</select><br />'."\n";
- }
- return ($possdirs,$output);
+END
}
=pod
Index: loncom/interface/londocs.pm
diff -u loncom/interface/londocs.pm:1.689 loncom/interface/londocs.pm:1.690
--- loncom/interface/londocs.pm:1.689 Sat Dec 17 18:07:47 2022
+++ loncom/interface/londocs.pm Sat Dec 31 14:08:59 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Documents
#
-# $Id: londocs.pm,v 1.689 2022/12/17 18:07:47 raeburn Exp $
+# $Id: londocs.pm,v 1.690 2022/12/31 14:08:59 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -6294,12 +6294,12 @@
SEDFFORM
my $importcrsresform;
my ($numdirs,$pickfile) =
- &Apache::loncommon::import_crsauthor_form('crsresimportform','coursepath','coursefile',
+ &Apache::loncommon::import_crsauthor_form('coursepath','coursefile',
"resize_scrollbox('contentscroll','1','0');",
undef,'res');
if ($pickfile) {
$importcrsresform=(<<CRSFORM);
- <a class="LC_menubuttons_link" href="javascript:toggleImportCrsres('res','$numdirs');">
+ <a class="LC_menubuttons_link" href="javascript:toggleImportCrsres('res');">
$lt{'imcr'}</a>$help{'Course_Resources'}
<form action="/adm/coursedocs" method="post" name="crsresimportform" onsubmit="return validImportCrsRes();">
<fieldset id="importcrsresform" style="display: none;">
@@ -6310,7 +6310,7 @@
$lt{'title'}: <input type="textbox" name="crsrestitle" value="" $disabled />
</p>
<input type="hidden" name="importdetail" value="" />
- <input type="submit" name="crsres" value="$lt{'impo'}" $disabled />
+ <input type="submit" name="crsres" value="$lt{'impo'}" $disabled /><br />
</fieldset>
</form>
CRSFORM
@@ -6330,7 +6330,7 @@
{ '<img class="LC_noBorder LC_middle" src="/res/adm/pages/sequence.png" alt="'.$lt{impm}.'" onclick="javascript:toggleMap(\'map\');" />' => $importpubform },
);
if ($pickfile) {
- push(@importpubforma,{ '<img class="LC_noBorder LC_middle" src="/res/adm/pages/res.png" alt="'.$lt{imcr}.'" onclick="javascript:toggleImportCrsres(\'res\','."'$numdirs'".');"/>' => $importcrsresform});
+ push(@importpubforma,{ '<img class="LC_noBorder LC_middle" src="/res/adm/pages/res.png" alt="'.$lt{imcr}.'" onclick="javascript:toggleImportCrsres(\'res\');" />' => $importcrsresform});
}
$importpubform = &create_form_ul(&create_list_elements(@importpubforma));
my $extresourcesform =
@@ -6537,16 +6537,16 @@
my $numcrsdirs = 0;
my ($showstdprob,$showswitch,$switchlink);
my $toppath = "/priv/$env{'user.domain'}/$env{'user.name'}";
+ my $exclude = &Apache::lonnet::priv_exclude();
if ($env{'user.author'}) {
$numauthor ++;
$select_menus{'author'}->{'text'} = &Apache::lonnet::plaintext('au');
if (grep(/^\Q$env{'user.home'}\E$/, at ids)) {
my $is_home = 1;
my %subdirs;
- &Apache::lonnet::recursedirs($is_home,'priv',$londocroot,$toppath,'',\%subdirs);
+ &Apache::lonnet::recursedirs($is_home,1,'',$exclude,0,$toppath,'',\%subdirs);
$select_menus{'author'}->{'default'} = '/';
- $select_menus{'author'}->{'select2'}->{'/'} = '/';
- my @ordered = ('/');
+ my @ordered = ();
foreach my $relpath (sort { lc($a) cmp lc($b) } (keys(%subdirs))) {
$select_menus{'author'}->{'select2'}->{$relpath} = $relpath;
push(@ordered,$relpath);
@@ -6578,10 +6578,8 @@
my $is_home = 1;
my (%subdirs, at ordered);
my $toppath="/priv/$audom/$auname";
- &Apache::lonnet::recursedirs($is_home,'priv',$londocroot,$toppath,'',\%subdirs);
+ &Apache::lonnet::recursedirs($is_home,1,'',$exclude,0,$toppath,'',\%subdirs);
$select_menus{$key}->{'default'} = '/';
- $select_menus{$key}->{'select2'}->{'/'} = '/';
- my @ordered = ('/');
foreach my $relpath (sort { lc($a) cmp lc($b) } (keys(%subdirs))) {
$select_menus{$key}->{'select2'}->{$relpath} = $relpath;
push(@ordered,$relpath);
@@ -6626,11 +6624,10 @@
my $is_home = 1;
my %subdirs;
my $toppath="/priv/$coursedom/$coursenum";
- &Apache::lonnet::recursedirs($is_home,'priv',$londocroot,$toppath,'',\%subdirs);
+ &Apache::lonnet::recursedirs($is_home,1,'',$exclude,0,$toppath,'',\%subdirs);
$numcrsdirs = keys(%subdirs);
$select_menus{'course'}->{'default'} = '/';
- $select_menus{'course'}->{'select2'}->{'/'} = '/';
- my @ordered = ('/');
+ my @ordered = ();
foreach my $relpath (sort { lc($a) cmp lc($b) } (keys(%subdirs))) {
$select_menus{'course'}->{'select2'}->{$relpath} = $relpath;
push(@ordered,$relpath);
@@ -6658,7 +6655,7 @@
$pickdir .= '<input type="hidden" name="authorrole" value="course" />';
my $toppath="/priv/$coursedom/$coursenum'}";
my %subdirs;
- &Apache::lonnet::recursedirs($is_home,'priv',$londocroot,$toppath,'',\%subdirs);
+ &Apache::lonnet::recursedirs($is_home,1,'',$exclude,0,$toppath,'',\%subdirs);
$numcrsdirs = keys(%subdirs);
if ($numcrsdirs) {
$pickdir .= $lt{'dire'}.' <select name="authorpath">'."\n".
@@ -6679,7 +6676,7 @@
$select_menus{'course'}->{'default'} = 'switch';
$select_menus{'course'}->{'order'} = ['switch'];
push(@order,'course');
- my $defrole;
+ my $defrole = 'course';
$pickdir = $lt{'loca'}.
&Apache::loncommon::linked_select_forms('courseresform','<br />'.$lt{'dire'},
$defrole,'authorrole','authorpath',
@@ -7530,7 +7527,7 @@
my $backtourl;
my $toplevelmain = &escape(&default_folderpath($coursenum,$coursedom,$navmapref));
my $toplevelsupp = &supplemental_base();
-
+ my $showfile_js = &Apache::loncommon::show_crsfiles_js();
if ($env{'docs.exit.'.$env{'request.course.id'}} =~ /^direct_(.+)$/) {
my $caller = $1;
if ($caller =~ /^supplemental/) {
@@ -8056,17 +8053,14 @@
}
}
-function toggleImportCrsres(caller,dircount) {
+function toggleImportCrsres(caller) {
var disp = 'none';
if (document.getElementById('importcrsresform')) {
if (caller == 'res') {
- var numdirs = parseInt(dircount);
var curr = document.getElementById('importcrsresform').style.display;
if (curr == 'none') {
disp='block';
- if (numdirs > 1) {
- select1res_changed();
- }
+ populateCrsSelects(document.crsresimportform,'coursepath','coursefile',1,'',1,0,1,1);
}
}
document.getElementById('importcrsresform').style.display=disp;
@@ -8075,6 +8069,8 @@
return;
}
+$showfile_js
+
function switchForProb() {
if (document.courseresform.authorpath.options[document.courseresform.authorpath.selectedIndex].value == 'switch') {
var url = '/adm/switchserver?otherserver=';
Index: loncom/homework/edit.pm
diff -u loncom/homework/edit.pm:1.155 loncom/homework/edit.pm:1.156
--- loncom/homework/edit.pm:1.155 Wed Oct 4 12:55:09 2017
+++ loncom/homework/edit.pm Sat Dec 31 14:08:59 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# edit mode helpers
#
-# $Id: edit.pm,v 1.155 2017/10/04 12:55:09 raeburn Exp $
+# $Id: edit.pm,v 1.156 2022/12/31 14:08:59 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1225,32 +1225,27 @@
$allonly = $crsonly;
}
my ($numdirs,$pickfile) =
- &Apache::loncommon::import_crsauthor_form($form,'coursepath_'.$element,'coursefile_'.$element,undef,$allonly,$element);
- if ($pickfile) {
- $importcrsres=(<<CRSRES);
+ &Apache::loncommon::import_crsauthor_form('coursepath_'.$element,'coursefile_'.$element,undef,$allonly,$element);
+ $importcrsres=(<<CRSRES);
<fieldset id="importcrsresform_$element" style="display:inline;">
<legend>$lt{'uacf'}</legend>
$pickfile
<input type="button" name="crsres" value="$lt{'sefi'}" onclick="updateCrsFile(this.form,'$element');" />
</fieldset>
CRSRES
- }
my %subdirs;
my $toppath="/priv/$cdom/$cnum";
- my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
- &Apache::lonnet::recursedirs(1,'priv',$londocroot,$toppath,'',\%subdirs);
+ my $exclude = &Apache::lonnet::priv_exclude();
+ &Apache::lonnet::recursedirs(1,1,'',$exclude,'',$toppath,'',\%subdirs);
my $numcrsdirs = keys(%subdirs);
- my $pickdir;
- if ($numcrsdirs) {
- $pickdir = $lt{'dire'}.'<select name="crsauthorpath_'.$element.'">'."\n".
+ my $pickdir = $lt{'dire'}.'<select name="crsauthorpath_'.$element.'">'."\n".
'<option value="/">/</option>'."\n";
+ if ($numcrsdirs) {
foreach my $key (sort { lc($a) cmp lc($b) } (keys(%subdirs))) {
$pickdir .= '<option value="'.$key.'">'.$key.'</option>'."\n";
}
- $pickdir .= '</select><br />';
- } else {
- $pickdir = '<input type="hidden" name="crsauthorpath_'.$element.'" value="/" />'."\n";
}
+ $pickdir .= '</select><br />';
my $uploadfile =(<<CRSUPL);
<fieldset id="uploadcrsresform_$element" style="display:inline;">
<legend>$lt{'uanf'}</legend>
@@ -1278,12 +1273,10 @@
$output = '<a href="javascript:toggleChooser(document.'.$form.",'$element'".');">'.
&mt('Choose File').'</a>'.
'<div id="chooser_'.$element.'" style="display:none" class="LC_left_float">'.
- '<fieldset><legend>'.&mt('Choose File').'</legend>';
- if ($numdirs) {
- $output .= '<label><input type="radio" name="chooser_'.$element.'" value="crsres" onclick="toggleCrsFile(this.form,'."'$element','$numdirs'".')" />'.$lt{'uacf'}.'</label> ';
- }
- $output .= '<label><input type="radio" name="chooser_'.$element.'" value="upload" onclick="toggleCrsUpload(this.form,'."'$element','$numcrsdirs'".')" />'.$lt{'uanf'}.'</label> '.
- '<label><input type="radio" name="chooser_'.$element.'" value="import" onclick="toggleResImport(this.form,'."'$element'".');openbrowser('."'$form','$element'$bretitleelement)".'" />'.$lt{'impo'}.'</label>';
+ '<fieldset><legend>'.&mt('Choose File').'</legend>'.
+ '<label><input type="radio" name="chooser_'.$element.'" value="crsres" onclick="toggleCrsFile(this.form,'."'$element'".')" />'.$lt{'uacf'}.'</label> '.
+ '<label><input type="radio" name="chooser_'.$element.'" value="upload" onclick="toggleCrsUpload(this.form,'."'$element'".')" />'.$lt{'uanf'}.'</label> '.
+ '<label><input type="radio" name="chooser_'.$element.'" value="import" onclick="toggleResImport(this.form,'."'$element'".');openbrowser('."'$form','$element'$bretitleelement)".'" />'.$lt{'impo'}.'</label>';
if ($usesearch) {
$output .= ' <label><input type="radio" name="chooser_'.$element.'" value="search" onclick="opensearcher('."'$form','$element'$srchtitleelement".')" />'.$lt{'sear'}.'</label>';
}
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1502 loncom/lonnet/perl/lonnet.pm:1.1503
--- loncom/lonnet/perl/lonnet.pm:1.1502 Wed Nov 23 02:55:37 2022
+++ loncom/lonnet/perl/lonnet.pm Sat Dec 31 14:09:00 2022
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1502 2022/11/23 02:55:37 raeburn Exp $
+# $Id: lonnet.pm,v 1.1503 2022/12/31 14:09:00 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -2924,7 +2924,7 @@
if (&auto_instcode_format($caller,$dom,\%coursecodes,\%codes,
\@codetitles,\%cat_titles,\%cat_order) eq 'ok') {
$instcats = {
- totcodes => $totcodes,
+ totcodes => $totcodes,
codes => \%codes,
codetitles => \@codetitles,
cat_titles => \%cat_titles,
@@ -12026,14 +12026,19 @@
# or corresponding Published Resource Space, and populate the hash ref:
# $dirhashref with URLs of all directories, and if $filehashref hash
# ref arg is provided, the URLs of any files, excluding versioned, .meta,
-# or .rights files in resource space, and .meta, .save, .log, and .bak
-# files in Authoring Space.
+# or .rights files in resource space, and .meta, .save, .log, .bak and
+# .rights files in Authoring Space.
#
# Inputs:
#
# $is_home - true if current server is home server for user's space
-# $context - either: priv, or res respectively for Authoring or Resource Space.
-# $docroot - Document root (i.e., /home/httpd/html
+# $recurse - if true will also traverse subdirectories recursively
+# $include - reference to hash containing allowed file extensions. If provided,
+# files which do not have a matching extension will be ignored.
+# $exclude - reference to hash containing excluded file extensions. If provided,
+# files which have a matching extension will be ignored.
+# $nonemptydir - if true, will only populate $fileshashref hash entry for a particular
+# directory with first file found (with acceptable extension).
# $toppath - Top level directory (i.e., /res/$dom/$uname or /priv/$dom/$uname
# $relpath - Current path (relative to top level).
# $dirhashref - reference to hash to populate with URLs of directories (Required)
@@ -12050,39 +12055,61 @@
#
sub recursedirs {
- my ($is_home,$context,$docroot,$toppath,$relpath,$dirhashref,$filehashref) = @_;
+ my ($is_home,$recurse,$include,$exclude,$nonemptydir,$toppath,$relpath,$dirhashref,$filehashref) = @_;
return unless (ref($dirhashref) eq 'HASH');
+ my $docroot = $perlvar{'lonDocRoot'};
my $currpath = $docroot.$toppath;
- if ($relpath) {
+ if ($relpath ne '') {
$currpath .= "/$relpath";
}
- my $savefile;
+ my ($savefile,$checkinc,$checkexc);
if (ref($filehashref)) {
$savefile = 1;
}
+ if (ref($include) eq 'HASH') {
+ $checkinc = 1;
+ }
+ if (ref($exclude) eq 'HASH') {
+ $checkexc = 1;
+ }
if ($is_home) {
if (opendir(my $dirh,$currpath)) {
+ my $filecount = 0;
foreach my $item (sort { lc($a) cmp lc($b) } grep(!/^\.+$/,readdir($dirh))) {
next if ($item eq '');
if (-d "$currpath/$item") {
my $newpath;
- if ($relpath) {
+ if ($relpath ne '') {
$newpath = "$relpath/$item";
} else {
$newpath = $item;
}
$dirhashref->{&Apache::lonlocal::js_escape($newpath)} = 1;
- &recursedirs($is_home,$context,$docroot,$toppath,$newpath,$dirhashref,$filehashref);
- } elsif ($savefile) {
- if ($context eq 'priv') {
- unless ($item =~ /\.(meta|save|log|bak|DS_Store)$/) {
- $filehashref->{&Apache::lonlocal::js_escape($relpath)}{$item} = 1;
- }
- } else {
- unless (($item =~ /\.meta$/) || ($item =~ /\.\d+\.\w+$/) || ($item =~ /\.rights$/)) {
+ if ($recurse) {
+ &recursedirs($is_home,$recurse,$include,$exclude,$nonemptydir,$toppath,$newpath,$dirhashref,$filehashref);
+ }
+ } elsif (($savefile) || ($relpath eq '')) {
+ next if ($nonemptydir && $filecount);
+ if ($checkinc || $checkexc) {
+ my ($extension) = ($item =~ /\.(\w+)$/);
+ if ($checkinc) {
+ next unless ($extension && $include->{$extension});
+ }
+ if ($checkexc) {
+ next if ($extension && $exclude->{$extension});
+ }
+ }
+ if (($relpath eq '') && (!exists($dirhashref->{'/'}))) {
+ $dirhashref->{'/'} = 1;
+ }
+ if ($savefile) {
+ if ($relpath eq '') {
+ $filehashref->{'/'}{$item} = 1;
+ } else {
$filehashref->{&Apache::lonlocal::js_escape($relpath)}{$item} = 1;
}
}
+ $filecount ++;
}
}
closedir($dirh);
@@ -12093,6 +12120,7 @@
my @dir_lines;
my $dirptr=16384;
if (ref($dirlistref) eq 'ARRAY') {
+ my $filecount = 0;
foreach my $dir_line (sort
{
my ($afile)=split('&',$a,2);
@@ -12108,21 +12136,34 @@
if ($relpath) {
$newpath = "$relpath/$item";
} else {
- $relpath = '/';
$newpath = $item;
}
$dirhashref->{&Apache::lonlocal::js_escape($newpath)} = 1;
- &recursedirs($is_home,$context,$docroot,$toppath,$newpath,$dirhashref,$filehashref);
- } elsif ($savefile) {
- if ($context eq 'priv') {
- unless ($item =~ /\.(meta|save|log|bak|DS_Store)$/) {
- $filehashref->{$relpath}{$item} = 1;
- }
- } else {
- unless (($item =~ /\.meta$/) || ($item =~ /\.\d+\.\w+$/)) {
- $filehashref->{$relpath}{$item} = 1;
+ if ($recurse) {
+ &recursedirs($is_home,$recurse,$include,$exclude,$nonemptydir,$toppath,$newpath,$dirhashref,$filehashref);
+ }
+ } elsif (($savefile) || ($relpath eq '')) {
+ next if ($nonemptydir && $filecount);
+ if ($checkinc || $checkexc) {
+ my $extension;
+ if ($checkinc) {
+ next unless ($extension && $include->{$extension});
+ }
+ if ($checkexc) {
+ next if ($extension && $exclude->{$extension});
+ }
+ }
+ if (($relpath eq '') && (!exists($dirhashref->{'/'}))) {
+ $dirhashref->{'/'} = 1;
+ }
+ if ($savefile) {
+ if ($relpath eq '') {
+ $filehashref->{'/'}{$item} = 1;
+ } else {
+ $filehashref->{&Apache::lonlocal::js_escape($relpath)}{$item} = 1;
}
}
+ $filecount ++;
}
}
}
@@ -12130,6 +12171,17 @@
return;
}
+sub priv_exclude {
+ return {
+ meta => 1,
+ save => 1,
+ log => 1,
+ bak => 1,
+ rights => 1,
+ DS_Store => 1,
+ };
+}
+
# -------------------------------------------------------- Value of a Condition
# gets the value of a specific preevaluated condition
Index: loncom/loncapa_apache.conf
diff -u loncom/loncapa_apache.conf:1.278 loncom/loncapa_apache.conf:1.279
--- loncom/loncapa_apache.conf:1.278 Thu Jun 30 21:04:15 2022
+++ loncom/loncapa_apache.conf Sat Dec 31 14:09:01 2022
@@ -2,7 +2,7 @@
## loncapa_apache.conf -- Apache HTTP LON-CAPA configuration file
##
-# $Id: loncapa_apache.conf,v 1.278 2022/06/30 21:04:15 raeburn Exp $
+# $Id: loncapa_apache.conf,v 1.279 2022/12/31 14:09:01 raeburn Exp $
#
# LON-CAPA Section (extensions to httpd.conf daemon configuration)
@@ -765,6 +765,17 @@
ErrorDocument 500 /adm/errorhandler
</Location>
+<Location /adm/courseauthor>
+AuthType LONCAPA
+Require valid-user
+PerlAuthzHandler Apache::lonacc
+SetHandler perl-script
+PerlHandler Apache::loncourseauthor
+ErrorDocument 403 /adm/login
+ErrorDocument 406 /adm/roles
+ErrorDocument 500 /adm/errorhandler
+</Location>
+
<Location /adm/login>
SetHandler perl-script
PerlHandler Apache::lonlogin
Index: doc/loncapafiles/loncapafiles.lpml
diff -u doc/loncapafiles/loncapafiles.lpml:1.1034 doc/loncapafiles/loncapafiles.lpml:1.1035
--- doc/loncapafiles/loncapafiles.lpml:1.1034 Tue Oct 4 20:39:58 2022
+++ doc/loncapafiles/loncapafiles.lpml Sat Dec 31 14:09:02 2022
@@ -2,7 +2,7 @@
"http://lpml.sourceforge.net/DTD/lpml.dtd">
<!-- loncapafiles.lpml -->
-<!-- $Id: loncapafiles.lpml,v 1.1034 2022/10/04 20:39:58 raeburn Exp $ -->
+<!-- $Id: loncapafiles.lpml,v 1.1035 2022/12/31 14:09:02 raeburn Exp $ -->
<!--
@@ -2516,6 +2516,16 @@
<status>works/unverified</status>
</file>
<file>
+<source>loncom/interface/loncourseauthor.pm</source>
+<target dist='default'>home/httpd/lib/perl/Apache/loncourseauthor.pm</target>
+<categoryname>handler</categoryname>
+<description>
+Support ajax requests with json response for listing of directories and/or files
+stored in /home/httpd/html/priv/<domain>/<courseID> on course's home sever.
+</description>
+<status>works/unverified</status>
+</file>
+<file>
<source>loncom/interface/lonchat.pm</source>
<target dist='default'>home/httpd/lib/perl/Apache/lonchat.pm</target>
<categoryname>handler</categoryname>
Index: loncom/interface/loncourseauthor.pm
+++ loncom/interface/loncourseauthor.pm
# The LearningOnline Network
# Documents
#
# $Id: loncourseauthor.pm,v 1.1 2022/12/31 14:08:59 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
package Apache::loncourseauthor;
use strict;
use Apache::Constants qw(:common :http);
use Apache::lonnet;
use Apache::loncommon;
use JSON::DWIW;
use LONCAPA qw(:DEFAULT :match);
sub handler {
my $r = shift;
&Apache::loncommon::content_type($r,'application/json');
$r->send_http_header;
my ($nonemptydir,%dirhash,%filehash);
if ($env{'request.course.id'}) {
if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) {
my ($context,$recurse,$role,$is_home,$inc,$exc,$toppath,$relpath,
$include,$exclude);
if ($env{'form.role'}) {
$role = $env{'form.role'};
if ($env{'form.rec'}) {
$recurse = 1;
}
if ($env{'form.res'}) {
$context = 'res';
} else {
$context = 'priv';
}
if ($env{'form.inc'}) {
$inc = $env{'form.inc'};
$inc =~ s/^\s+|\s+$//g;
}
if ($env{'form.exc'}) {
$exc = $env{'form.exc'};
$exc =~ s/^\s+|\s+$//g;
}
if ($env{'form.nonempty'}) {
$nonemptydir = 1;
}
my $now = time;
my @ids=&Apache::lonnet::current_machine_ids();
if ($role eq 'author') {
if (exists($env{"user.role.au./$env{'user.domain'}/"})) {
my ($start,$end) = split(/\./,$env{"user.role.au./$env{'user.domain'}/"});
unless (($start && $start > $now) || ($end && $end < $now)) {
$toppath = "/$context/$env{'user.domain'}/$env{'user.name'}";
if (grep(/^\Q$env{'user.home'}\E$/, at ids)) {
$is_home = 1;
}
}
}
} elsif ($role eq 'course') {
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
if (($cdom ne '') && ($cnum ne '')) {
$toppath = "/$context/$cdom/$cnum";
my $rolehome = &Apache::lonnet::homeserver($cnum,$cdom);
if (grep(/^\Q$rolehome\E$/, at ids)) {
$is_home = 1;
}
}
} elsif ($role =~ m{^(ca|aa)\./($match_domain)/($match_username)$}) {
my ($rolecode,$audom,$auname) = ($1,$2,$3);
if (exists($env{"user.role.$role"})) {
my ($start,$end) = split(/\./,$env{"user.role.$role"});
unless(($start && $start > $now) || ($end && $end < $now)) {
$toppath = "/$context/$audom/$auname";
my $rolehome = &Apache::lonnet::homeserver($auname,$audom);
if (grep(/^\Q$rolehome\E$/, at ids)) {
$is_home = 1;
}
}
}
}
if ($toppath ne '') {
if ($env{'form.path'}) {
$relpath = $env{'form.path'};
}
my @ids=&Apache::lonnet::current_machine_ids();
if (grep(/^\Q$env{'user.home'}\E$/, at ids)) {
$is_home = 1;
}
if ($inc) {
map { $include->{$_} = 1; } split(/\s*,\s*/,$inc);
}
if ($exc) {
map { $exclude->{$_} = 1; } split(/\s*,\s*/,$exc);
}
my $dirhashref = \%dirhash;
my $filehashref;
if ($env{'form.files'}) {
$filehashref = \%filehash;
}
&Apache::lonnet::recursedirs($is_home,$recurse,$include,$exclude,$nonemptydir,
$toppath,$relpath,$dirhashref,$filehashref);
}
}
}
}
my @dirs = ();
if (%dirhash) {
if ($dirhash{'/'}) {
push(@dirs,'/');
delete($dirhash{'/'});
}
if ($nonemptydir) {
foreach my $dir (sort { lc($a) cmp lc($b) } (keys(%dirhash))) {
next unless (ref($filehash{$dir}) eq 'HASH');
push(@dirs,$dir);
}
} else {
push(@dirs,(sort { lc($a) cmp lc($b) } (keys(%dirhash))));
}
}
my %files;
if (%filehash) {
foreach my $dir (keys(%filehash)) {
if (ref($filehash{$dir}) eq 'HASH') {
foreach my $key (keys(%{$filehash{$dir}})) {
if ($key =~ /\./) {
my $ext = (split(/\./,$key))[-1];
delete($filehash{$dir}{$key}) if ($ext eq 'rights');
}
}
my @names = sort { lc($a) cmp lc($b) } (keys(%{$filehash{$dir}}));
$files{$dir} = \@names;
}
}
}
$r->print(JSON::DWIW->to_json({dirs => \@dirs,
files => \%files}));
return OK;
}
1;
More information about the LON-CAPA-cvs
mailing list