diff --git a/conf/defaults.config b/conf/defaults.config index 08fbd048ed..ee219e01cf 100644 --- a/conf/defaults.config +++ b/conf/defaults.config @@ -1042,20 +1042,14 @@ $pg{additionalPGEditorDisplayModes} = [ # Whether the homework editor pages should show options for conditional release $options{enableConditionalRelease} = 0; -# In the set manager, how deep to search within templates for .def files. -# Note that this does not apply to the Library and Contrib directories. -# Those directories are not searched in any case (see below). -# 0 means only within templates. +########################################################################################## +# Searching for set.def files to import +########################################################################################## +# In the set manager and the library browser, the directory depth to search +# within templates for .def files. Note that this does not apply to the Library +# and Contrib directories. Those directories are not searched in any case. $options{setDefSearchDepth} = 4; -# In the set manager, also list OPL or Contrib set defintion files. Note -# that the directories are not searched, but these lists are loaded from the -# files htdocs/DATA/library-set-defs.json and htdocs/DATA/contrib-set-defs.json -# which are generated by running bin/generate-OPL-set-def-lists.pl (which is -# also run if you run bin/OPL-update). -$options{useOPLdefFiles} = 1; -$options{useContribDefFiles} = 1; - ########################################################################################## #### Default settings for the problem editor pages ########################################################################################## diff --git a/conf/localOverrides.conf.dist b/conf/localOverrides.conf.dist index d3e2e5c529..02b3f88e39 100644 --- a/conf/localOverrides.conf.dist +++ b/conf/localOverrides.conf.dist @@ -646,12 +646,11 @@ $mail{feedbackRecipients} = [ ################################################################################ # Searching for set.def files to import ################################################################################ -## Uncomment below so that when the Library Browser searches for set def -## files, it searches beyond templates; it can search deeper subfolders of -## templates, and optionally also descend into Library +# In the set manager and the library browser, the directory depth to search +# within templates for .def files. Note that this does not apply to the Library +# and Contrib directories. Those directories are not searched in any case. -#$options{setDefSearchDepth}=4; #search down 4 levels -#$options{useOPLdefFiles}=1; +#$options{setDefSearchDepth} = 4; ################################################################################ # Permission overrides (e.g. "admin", "professor", "ta", "student", "guest" diff --git a/htdocs/js/ProblemSetList/problemsetlist.js b/htdocs/js/ProblemSetList/problemsetlist.js index 4af5a7cc1d..c2802ebc9e 100644 --- a/htdocs/js/ProblemSetList/problemsetlist.js +++ b/htdocs/js/ProblemSetList/problemsetlist.js @@ -235,7 +235,7 @@ } }) ], - onReady(selectedDates) { + onReady() { // Flatpickr hides the original input and adds the alternate input after it. That messes up the // bootstrap input group styling. So move the now hidden original input after the created alternate // input to fix that. @@ -277,4 +277,42 @@ } }); } + + const importSourceSelect = document.getElementById('import_source_select'); + const listOPLSetsCheck = document.getElementById('list_opl_sets'); + const listContribSetsCheck = document.getElementById('list_contrib_sets'); + + if (importSourceSelect && (listOPLSetsCheck || listContribSetsCheck)) { + const allOptions = Array.from(importSourceSelect.options); + + const updateAvailableOptions = () => { + // Save the currently selected options. + const selectedDefs = Array.from(importSourceSelect.selectedOptions); + + for (const option of Array.from(importSourceSelect.options)) option.value && option.remove(); + for (const option of allOptions) { + if (option.value.startsWith('Library/')) { + if (listOPLSetsCheck.checked) importSourceSelect.add(option); + } else if (option.value.startsWith('Contrib/')) { + if (listContribSetsCheck.checked) importSourceSelect.add(option); + } else importSourceSelect.add(option); + } + + // Reselect the options that were selected before if still available. Otherwise + // select the first option which should be the "Select filenames below" option. + let foundSelected = false; + for (const option of importSourceSelect.options) { + if (selectedDefs.includes(option)) { + foundSelected = true; + option.selected = true; + } + } + if (!foundSelected) allOptions[0].selected = true; + }; + + listOPLSetsCheck?.addEventListener('change', updateAvailableOptions); + listContribSetsCheck?.addEventListener('change', updateAvailableOptions); + + updateAvailableOptions(); + } })(); diff --git a/htdocs/js/SetMaker/setmaker.js b/htdocs/js/SetMaker/setmaker.js index 581c165371..f358bfc874 100644 --- a/htdocs/js/SetMaker/setmaker.js +++ b/htdocs/js/SetMaker/setmaker.js @@ -509,4 +509,39 @@ document .querySelectorAll('.lb-problem-add [data-bs-toggle], .lb-problem-icons [data-bs-toggle=tooltip]') .forEach((el) => new bootstrap.Tooltip(el, { fallbackPlacements: [] })); + + // If this is the browse setdef panel, then set up the check boxes for including OPL or Contrib sets. + const setDefSelect = document.getElementsByName('library_sets')[0]; + const listOPLSetsCheck = document.getElementById('list_opl_sets'); + const listContribSetsCheck = document.getElementById('list_contrib_sets'); + + if (setDefSelect && (listOPLSetsCheck || listContribSetsCheck)) { + const allOptions = Array.from(setDefSelect.options); + + const updateAvailableOptions = () => { + // Save the currently selected option. + let selectedDef = setDefSelect.selectedOptions[0]; + + for (const option of Array.from(setDefSelect.options)) option.value && option.remove(); + for (const option of allOptions) { + if (option.value.startsWith('Library/')) { + if (listOPLSetsCheck.checked) setDefSelect.add(option); + else if (selectedDef === option) selectedDef = null; + } else if (option.value.startsWith('Contrib/')) { + if (listContribSetsCheck.checked) setDefSelect.add(option); + else if (selectedDef === option) selectedDef = null; + } else setDefSelect.add(option); + } + + // Reselect the option that was selected before if it is still available. Otherwise + // select the first option which should be the "Select a Set Defintion File" option. + if (selectedDef) selectedDef.selected = true; + else allOptions[0].selected = true; + }; + + listOPLSetsCheck?.addEventListener('change', updateAvailableOptions); + listContribSetsCheck?.addEventListener('change', updateAvailableOptions); + + updateAvailableOptions(); + } })(); diff --git a/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm b/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm index d45f25b9b0..e15b2dff18 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm @@ -471,7 +471,7 @@ sub pre_header_initialize ($c) { $count++ if ($j > 0); # Default of which problem selector to display - my $browse_which = $c->param('browse_which') || 'browse_npl_library'; + my $browse_which = $c->param('browse_which') || 'browse_opl'; # Check for problem lib buttons my $browse_lib = ''; @@ -484,7 +484,7 @@ sub pre_header_initialize ($c) { # Start the logic through if elsif elsif ... debug("browse_lib", $c->param("$browse_lib")); - debug("browse_npl_library", $c->param("browse_npl_library")); + debug("browse_opl", $c->param("browse_opl")); debug("browse_course_sets", $c->param("browse_course_sets")); debug("browse_setdefs", $c->param("browse_setdefs")); # Asked to browse certain problems @@ -493,8 +493,8 @@ sub pre_header_initialize ($c) { $c->{current_library_set} = ""; $use_previous_problems = 0; @pg_files = (); - } elsif ($c->param('browse_npl_library')) { - $browse_which = 'browse_npl_library'; + } elsif ($c->param('browse_opl')) { + $browse_which = 'browse_opl'; $c->{current_library_set} = ""; $use_previous_problems = 0; @pg_files = (); diff --git a/lib/WeBWorK/Utils/Instructor.pm b/lib/WeBWorK/Utils/Instructor.pm index 0c5de936c8..cb651e03af 100644 --- a/lib/WeBWorK/Utils/Instructor.pm +++ b/lib/WeBWorK/Utils/Instructor.pm @@ -671,33 +671,45 @@ sub getDefList { my @found_set_defs; - # get_set_defs_wanted is a closure over @found_set_defs - my $get_set_defs_wanted = sub { - if ($File::Find::dir =~ /^$topdir\/Library/ || $File::Find::dir =~ /^$topdir\/Contrib/) { - $File::Find::prune = 1; - return; - } - if (@{ [ $File::Find::dir =~ /\//g ] } > $max_depth) { $File::Find::prune = 1; return; } - push @found_set_defs, $_ =~ s|^$topdir/?||r if m|/set[^/]*\.def$|; - }; - - find({ wanted => $get_set_defs_wanted, follow_fast => 1, no_chdir => 1, follow_skip => 2 }, $topdir); + find( + { + wanted => sub { + if ($File::Find::dir =~ /^$topdir\/Library/ + || $File::Find::dir =~ /^$topdir\/Contrib/ + || $File::Find::dir =~ /^$topdir\/capaLibrary/) + { + $File::Find::prune = 1; + return; + } + if (@{ [ $File::Find::dir =~ /\//g ] } > $max_depth) { $File::Find::prune = 1; return; } + push @found_set_defs, $_ =~ s|^$topdir/?||r if m|/set[^/]*\.def$|; + }, + follow_fast => 1, + no_chdir => 1, + follow_skip => 2 + }, + $topdir + ); # Load the OPL set definition files from the list file. push(@found_set_defs, loadSetDefListFile("$ce->{webworkDirs}{htdocs}/DATA/library-set-defs.json")) - if ($ce->{options}{useOPLdefFiles}); + if -d "$ce->{courseDirs}{templates}/Library" && -r "$ce->{courseDirs}{templates}/Library"; # Load the Contrib set definition files from the list file. push(@found_set_defs, loadSetDefListFile("$ce->{webworkDirs}{htdocs}/DATA/contrib-set-defs.json")) - if ($ce->{options}{useContribDefFiles}); + if -d "$ce->{courseDirs}{templates}/Contrib" && -r "$ce->{courseDirs}{templates}/Contrib"; + my @lib_order; my @depths; my @caps; for (@found_set_defs) { + push(@lib_order, $_ =~ m|^Library/| ? 2 : $_ =~ m|^Contrib/| ? 3 : 1); push @depths, scalar(@{ [ $_ =~ /\//g ] }); push @caps, uc($_); } - return @found_set_defs[ sort { $depths[$a] <=> $depths[$b] || $caps[$a] cmp $caps[$b] } 0 .. $#found_set_defs ]; + return @found_set_defs[ + sort { $lib_order[$a] <=> $lib_order[$b] || $depths[$a] <=> $depths[$b] || $caps[$a] cmp $caps[$b] } + 0 .. $#found_set_defs ]; } =back diff --git a/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep b/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep index f0543cf973..44b9de5075 100644 --- a/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep +++ b/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep @@ -15,7 +15,7 @@ class => 'col-form-label col-form-label-sm col-md-auto' =%>