Skip to content

Commit

Permalink
Merge branch 'develop' into feature/achievement-notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
drdrew42 authored Oct 30, 2023
2 parents 52140e3 + 46f2fcf commit 6499e40
Show file tree
Hide file tree
Showing 70 changed files with 2,279 additions and 2,179 deletions.
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ RUN apt-get update \
imagemagick \
iputils-ping \
jq \
libarchive-extract-perl \
libarchive-zip-perl \
libarray-utils-perl \
libc6-dev \
Expand Down Expand Up @@ -184,7 +185,7 @@ RUN apt-get update \
# ==================================================================
# Phase 4 - Install additional Perl modules from CPAN that are not packaged for Ubuntu or are outdated in Ubuntu.

RUN cpanm install Statistics::R::IO DBD::MariaDB Mojo::[email protected] Perl::Tidy@20220613 \
RUN cpanm install Statistics::R::IO DBD::MariaDB Mojo::[email protected] Perl::Tidy@20220613 Archive::Zip::SimpleZip \
&& rm -fr ./cpanm /root/.cpanm /tmp/*

# ==================================================================
Expand Down
3 changes: 2 additions & 1 deletion DockerfileStage1
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ RUN apt-get update \
imagemagick \
iputils-ping \
jq \
libarchive-extract-perl \
libarchive-zip-perl \
libarray-utils-perl \
libc6-dev \
Expand Down Expand Up @@ -146,7 +147,7 @@ RUN apt-get update \
# ==================================================================
# Phase 3 - Install additional Perl modules from CPAN that are not packaged for Ubuntu or are outdated in Ubuntu.

RUN cpanm install -n Statistics::R::IO DBD::MariaDB Mojo::[email protected] Perl::Tidy@20220613 \
RUN cpanm install -n Statistics::R::IO DBD::MariaDB Mojo::[email protected] Perl::Tidy@20220613 Archive::Zip::SimpleZip \
&& rm -fr ./cpanm /root/.cpanm /tmp/*

# ==================================================================
1 change: 1 addition & 0 deletions bin/check_modules.pl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ =head1 DESCRIPTION

my @modulesList = qw(
Archive::Zip
Archive::Zip::SimpleZip
Array::Utils
Benchmark
Carp
Expand Down
8 changes: 4 additions & 4 deletions bin/dev_scripts/update-localization-files
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ do
esac
done

if [ -z "$WEBWORK_ROOT" ] || [ -z "$PG_ROOT" ]; then
echo >&2 "You need to set both the WEBWORK_ROOT and PG_ROOT environment variables. Aborting."
if [ -z "$WEBWORK_ROOT" ]; then
echo >&2 "You need to set the WEBWORK_ROOT environment variable. Aborting."
exit 1
fi

Expand All @@ -53,9 +53,9 @@ LOCDIR=$WEBWORK_ROOT/lib/WeBWorK/Localize

cd $LOCDIR

echo "Updating $WEBWORK_ROOT/webwork2.pot"
echo "Updating $LOCDIR/webwork2.pot"

xgettext.pl -o webwork2.pot -D $WEBWORK_ROOT/lib -D $PG_ROOT/lib -D $PG_ROOT/macros -D $WEBWORK_ROOT/templates \
xgettext.pl -o webwork2.pot -D $WEBWORK_ROOT/lib -D $WEBWORK_ROOT/templates \
$WEBWORK_ROOT/conf/defaults.config $WEBWORK_ROOT/conf/LTIConfigValues.config

if $UPDATE_PO; then
Expand Down
7 changes: 4 additions & 3 deletions bin/dev_scripts/webwork2-morbo
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,10 @@ push(@watch,
"$webwork_root/lib", "$webwork_root/templates", "$webwork_root/htdocs/js",
"$webwork_root/htdocs/themes", "$webwork_root/conf");

# Add the pg lib and pg htdocs directory if they are readable.
push(@watch, "$config->{pg_dir}/lib") if -r "$config->{pg_dir}/lib";
push(@watch, "$config->{pg_dir}/htdocs") if -r "$config->{pg_dir}/htdocs";
# Add the pg lib and pg htdocs directory and the PG.pl macro if they are readable.
push(@watch, "$config->{pg_dir}/lib") if -r "$config->{pg_dir}/lib";
push(@watch, "$config->{pg_dir}/htdocs") if -r "$config->{pg_dir}/htdocs";
push(@watch, "$config->{pg_dir}/macros/PG.pl") if -r "$config->{pg_dir}/macros/PG.pl";

my $morbo = Mojo::Server::Morbo->new(silent => !$verbose);
$morbo->daemon->listen(\@listen) if @listen;
Expand Down
8 changes: 1 addition & 7 deletions conf/defaults.config
Original file line number Diff line number Diff line change
Expand Up @@ -1045,12 +1045,6 @@ $pg{options}{showEvaluatedAnswers} = 1;
# propogate to the main process. So this really should never be set to 0.
$pg{options}{catchWarnings} = 1;

# decorations for correct input blanks -- apparently you can't define and name attribute collections in a .css file
$pg{options}{correct_answer} = "{border-width:2;border-style:solid;border-color:#8F8}"; #matches resultsWithOutError class in math2.css

# decorations for incorrect input blanks
$pg{options}{incorrect_answer} = "{border-width:2;border-style:solid;border-color:#F55}"; #matches resultsWithError class in math2.css

##### Settings for various display modes

# "images" mode has several settings:
Expand Down Expand Up @@ -1258,7 +1252,7 @@ ${pg}{modules} = [
[qw(Applet MIME::Base64)],
[qw(PGcore PGalias PGresource PGloadfiles PGanswergroup PGresponsegroup Tie::IxHash)],
[qw(Locale::Maketext)],
[qw(WeBWorK::Localize)],
[qw(WeBWorK::PG::Localize)],
[qw(JSON)],
[qw(Rserve Class::Tiny IO::Handle)],
[qw(DragNDrop)],
Expand Down
2 changes: 1 addition & 1 deletion conf/site.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ $externalPrograms{rm} = "/bin/rm";
$externalPrograms{mkdir} = "/bin/mkdir";
$externalPrograms{tar} = "/bin/tar";
$externalPrograms{gzip} = "/bin/gzip";
$externalPrograms{git} = "/usr/bin/git";
$externalPrograms{git} = "/usr/bin/git";

####################################################
# equation rendering/hardcopy utiltiies
Expand Down
2 changes: 0 additions & 2 deletions htdocs/generate-assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,6 @@ if (argv.watchFiles) console.log('\x1b[32mEstablishing watches and performing in
chokidar.watch(['js', 'themes'], {
ignored: /layouts|\.min\.(js|css)$/,
cwd: __dirname, // Make sure all paths are given relative to the htdocs directory.
usePolling: true, // Needed to get changes to symlinks.
interval: 500,
awaitWriteFinish: { stabilityThreshold: 500 },
persistent: argv.watchFiles ? true : false
})
Expand Down
39 changes: 38 additions & 1 deletion htdocs/js/ActionTabs/actiontabs.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,48 @@
(() => {
const takeAction = document.getElementById('take_action');
const currentAction = document.getElementById('current_action');

document.querySelectorAll('.action-link').forEach((actionLink) => {
const currentAction = document.getElementById('current_action');
actionLink.addEventListener('show.bs.tab', () => {
if (takeAction) takeAction.value = actionLink.textContent;
if (currentAction) currentAction.value = actionLink.dataset.action;
});
});

// Submit the form when a sort header is clicked or enter or space is pressed when it has focus.
if (currentAction) {
for (const header of document.querySelectorAll('.sort-header')) {
const submitSortMethod = (e) => {
e.preventDefault();

currentAction.value = 'sort';

const sortInput = document.createElement('input');
sortInput.name = 'labelSortMethod';
sortInput.value = header.dataset.sortField;
sortInput.type = 'hidden';
currentAction.form.append(sortInput);

currentAction.form.submit();
};

header.addEventListener('click', submitSortMethod);
header.addEventListener('keydown', (e) => {
if (e.key === ' ' || e.key === 'Enter') submitSortMethod(e);
});

const orderToggleButton = header.parentElement.querySelector('button.sort-order');
orderToggleButton?.addEventListener('click', () => {
currentAction.value = 'sort';

const sortOrderInput = document.createElement('input');
sortOrderInput.name = 'labelSortOrder';
sortOrderInput.value = orderToggleButton.dataset.sortPriority;
sortOrderInput.type = 'hidden';
currentAction.form.append(sortOrderInput);

currentAction.form.submit();
});
}
}
})();
93 changes: 79 additions & 14 deletions htdocs/js/FileManager/filemanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,83 @@

document.getElementsByName('directory')[0]?.addEventListener('change', () => doAction('Go'));
document.getElementsByName('dates')[0]?.addEventListener('click', () => doAction('Refresh'));
files?.addEventListener('dblclick', () => doAction('View'));
files?.addEventListener('dblclick', () => {
if (files.selectedOptions[0].dataset.type & 0b11010) doAction('View');
else {
const container = document.createElement('div');
container.classList.add('toast-container', 'top-50', 'start-50', 'translate-middle');

const toast = document.createElement('div');
toast.classList.add('toast');
toast.setAttribute('role', 'alert');
toast.setAttribute('aria-live', 'assertive');
toast.setAttribute('aria-atomit', 'true');
const toastContent = document.createElement('div');
toastContent.classList.add('d-flex', 'alert', 'alert-danger', 'mb-0', 'p-0');

const toastBody = document.createElement('div');
toastBody.classList.add('toast-body');
toastBody.textContent =
files.selectedOptions[0].dataset.type & 0b1
? files.dataset.linkMessage || 'Symbolic links can not be followed.'
: files.dataset.nonViewableMessage || 'This is not a viewable file type.';

const closeButton = document.createElement('button');
closeButton.type = 'button';
closeButton.classList.add('btn-close', 'me-2', 'm-auto');
closeButton.dataset.bsDismiss = 'toast';
closeButton.setAttribute('aria-label', files.dataset.closeTitle || 'Close');

toastContent.append(toastBody, closeButton);

toast.append(toastContent);
container.append(toast);
document.body.append(container);

const bsToast = new bootstrap.Toast(toast);
bsToast.show();
toast.addEventListener('hidden.bs.toast', () => {
bsToast.dispose();
container.remove();
});
}
});

// If on the confirmation page, then focus the "name" input.
form.querySelector('input[name="name"]')?.focus();
}

const fileActionButtons = ['View', 'Edit', 'Download', 'Rename', 'Copy', 'Delete', 'MakeArchive'].map((buttonId) =>
document.getElementById(buttonId)
);
// The bits for types from least to most significant digit are set in the directoryListing method of
// lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm to mean a file is a
// link, directory, regular file, text file, or image file.
const fileActions = [
{ id: 'View', types: 0b11010, multiple: 0 },
{ id: 'Edit', types: 0b01000, multiple: 0 },
{ id: 'Download', types: 0b100, multiple: 0 },
{ id: 'Rename', types: 0b111, multiple: 0 },
{ id: 'Copy', types: 0b100, multiple: 0 },
{ id: 'Delete', types: 0b111, multiple: 1 },
{ id: 'MakeArchive', types: 0b111, multiple: 1 }
];
fileActions.map((button) => (button.elt = document.getElementById(button.id)));
const archiveButton = document.getElementById('MakeArchive');

const checkFiles = () => {
const state = files.selectedIndex < 0;
const selectedFiles = files.selectedOptions;

for (const button of fileActionButtons) {
if (button) button.disabled = state;
for (const button of fileActions) {
if (!button.elt) continue;
if (selectedFiles.length) {
if (selectedFiles.length == 1 && !button.multiple)
button.elt.disabled = !(button.types & selectedFiles[0].dataset.type);
else button.elt.disabled = !button.multiple;
} else {
button.elt.disabled = true;
}
}

if (archiveButton && !state) {
const numSelected = files.querySelectorAll('option:checked').length;
if (
numSelected === 0 ||
numSelected > 1 ||
!/\.(tar|tar\.gz|tgz)$/.test(files.children[files.selectedIndex].value)
)
if (archiveButton && selectedFiles.length) {
if (selectedFiles.length > 1 || !/\.(tar|tar\.gz|tgz|zip)$/.test(selectedFiles[0].value))
archiveButton.value = archiveButton.dataset.archiveText;
else archiveButton.value = archiveButton.dataset.unarchiveText;
}
Expand All @@ -45,6 +97,19 @@
files?.addEventListener('change', checkFiles);
if (files) checkFiles();

const archiveFilenameInput = document.getElementById('archive-filename');
const archiveTypeSelect = document.getElementById('archive-type');
if (archiveFilenameInput && archiveTypeSelect) {
archiveTypeSelect.addEventListener('change', () => {
if (archiveTypeSelect.value) {
archiveFilenameInput.value = archiveFilenameInput.value.replace(
/\.(zip|tgz|tar.gz)$/,
`.${archiveTypeSelect.value}`
);
}
});
}

const file = document.getElementById('file');
const uploadButton = document.getElementById('Upload');
const checkFile = () => (uploadButton.disabled = file.value === '');
Expand Down
4 changes: 4 additions & 0 deletions htdocs/js/PGCodeMirror/pgeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@
= CodeMirror.fromTextArea(document.querySelector('.codeMirrorEditor'), options);
cm.setSize('100%', '550px');

// Refresh the CodeMirror instance anytime the containing div resizes so that if line wrapping changes,
// the mouse cursor will still go to the correct place when the user clicks on the CodeMirror window.
new ResizeObserver(() => cm.refresh()).observe(document.querySelector('.CodeMirror'));

const currentThemeFile = localStorage.getItem('WW_PGEditor_selected_theme') ?? 'default';
const currentThemeName = await loadConfig(currentThemeFile);
cm.setOption('theme', currentThemeName);
Expand Down
9 changes: 5 additions & 4 deletions htdocs/js/ProblemGrader/problemgrader.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,16 @@
} else {
// Update the hidden problem status fields and score table for gateway quizzes
if (saveData.versionId !== '0') {
document.gwquiz.elements['probstatus' + saveData.problemId].value =
parseInt(scoreInput.value) / 100;
const probStatus = document.gwquiz.elements[`probstatus${saveData.problemId}`];
if (probStatus) probStatus.value = parseInt(scoreInput.value) / 100;
let testValue = 0;
for (const scoreCell of document.querySelectorAll('table.gwNavigation td.score')) {
if (scoreCell.dataset.problemId == saveData.problemId) {
scoreCell.textContent = scoreInput.value == '100' ? '\u{1F4AF}' : scoreInput.value;
}
testValue += document.gwquiz.elements['probstatus'
+ scoreCell.dataset.problemId].value * scoreCell.dataset.problemValue;
testValue +=
(document.gwquiz.elements[`probstatus${scoreCell.dataset.problemId}`]?.value ?? 0) *
scoreCell.dataset.problemValue;
}
const recordedScore = document.getElementById('test-recorded-score');
if (recordedScore) {
Expand Down
2 changes: 1 addition & 1 deletion htdocs/js/RenderProblem/renderproblem.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
send_pg_flags: 1,
extra_header_text:
'<style>' +
'html{overflow-y:hidden;}body{padding:1px;background:#f5f5f5;}.container-fluid{padding:0px;}' +
'html{overflow-y:auto;}body{padding:1px;background:#f5f5f5;}.container-fluid{padding:0px;}' +
'</style>',
...renderOptions
};
Expand Down
10 changes: 0 additions & 10 deletions htdocs/js/ShowHide/show_hide.js

This file was deleted.

2 changes: 1 addition & 1 deletion htdocs/js/TagWidget/tagwidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@
if (!response.ok) return showMessage('Unable to save problem tags.');
const data = await response.json();
if (data.error) return showMessage(data.error);
showMessage(data.server_response);
showMessage(data.server_response, true);
}
}

Expand Down
Loading

0 comments on commit 6499e40

Please sign in to comment.