diff --git a/htdocs/js/apps/Problem/problem.scss b/htdocs/js/apps/Problem/problem.scss
index ef76efc177..2da73fae53 100644
--- a/htdocs/js/apps/Problem/problem.scss
+++ b/htdocs/js/apps/Problem/problem.scss
@@ -60,7 +60,7 @@
line-height: 20px;
}
- select, input[type=text], input[type=radio] {
+ select, input[type=text], input[type=radio], input[type=checkbox] {
&.correct {
border-color: rgba(81, 153, 81, 0.8); /* green */
outline: 0;
diff --git a/macros/core/PGbasicmacros.pl b/macros/core/PGbasicmacros.pl
index c58d622077..215639b9b5 100644
--- a/macros/core/PGbasicmacros.pl
+++ b/macros/core/PGbasicmacros.pl
@@ -675,9 +675,11 @@ sub contained_in {
##########################
sub NAMED_ANS_CHECKBOX {
- my $name = shift;
- my $value = shift;
- my $tag = shift;
+ my $name = shift;
+ my $value = shift;
+ my $tag = shift;
+ my $extend = shift;
+ my %options = @_;
my $checked = '';
if ($value =~ /^\%/) {
@@ -693,17 +695,20 @@ sub NAMED_ANS_CHECKBOX {
}
}
- $name = RECORD_ANS_NAME($name, { $value => $checked });
+ $name = RECORD_ANS_NAME($name, { $value => $checked }) unless $extend;
+ INSERT_RESPONSE($options{answer_group_name}, $name, { $value => $checked }) if $extend;
my $label = generate_aria_label($name);
$label .= "option 1 ";
MODES(
TeX => qq!\\item{$tag}\n!,
- Latex2HTML =>
- qq!\\begin{rawhtml}\n\\end{rawhtml}$tag!,
- HTML =>
- qq!!,
- PTX => '
' . "$tag" . '' . "\n",
+ Latex2HTML => qq!\\begin{rawhtml}\n!
+ . qq!!
+ . qq!\\end{rawhtml}$tag!,
+ HTML => '!,
+ PTX => "$tag\n",
);
}
@@ -728,7 +733,7 @@ sub NAMED_ANS_CHECKBOX_OPTION {
}
}
- EXTEND_RESPONSE($name, $name, $value, $checked);
+ EXTEND_RESPONSE($options{answer_group_name} // $name, $name, $value, $checked);
my $label;
if (defined($options{aria_label})) {
$label = $options{aria_label};
@@ -738,11 +743,13 @@ sub NAMED_ANS_CHECKBOX_OPTION {
MODES(
TeX => qq!\\item{$tag}\n!,
- Latex2HTML =>
- qq!\\begin{rawhtml}\n\\end{rawhtml}$tag!,
- HTML =>
- qq!!,
- PTX => '' . "$tag" . '' . "\n",
+ Latex2HTML => qq!\\begin{rawhtml}\n!
+ . qq!!
+ . qq!\\end{rawhtml}$tag!,
+ HTML => '!,
+ PTX => "$tag\n",
);
}
diff --git a/macros/parsers/parserCheckboxList.pl b/macros/parsers/parserCheckboxList.pl
new file mode 100644
index 0000000000..09ff6c7014
--- /dev/null
+++ b/macros/parsers/parserCheckboxList.pl
@@ -0,0 +1,526 @@
+################################################################################
+# WeBWorK Online Homework Delivery System
+# Copyright © 2000-2022 The WeBWorK Project, https://github.com/openwebwork
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of either: (a) the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version, or (b) the "Artistic License" which comes with this package.
+#
+# This program 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 either the GNU General Public License or the
+# Artistic License for more details.
+################################################################################
+
+=head1 NAME
+
+parserCheckboxList.pl - Multiple choice checkbox answers compatible with
+ MathObjects, MultiAnswer objects, and PGML.
+
+=head1 DESCRIPTION
+
+This file implements a multiple choice checkbox object that is compatible with
+MathObjects, and in particular, with the MultiAnswer object, and with PGML.
+
+To create a CheckboxList object, use
+
+ $checks = CheckboxList([choices, ...], [correct_choices, ...], options);
+
+where "S" are the label value strings for the checkboxes,
+"S" are the choices that are the correct answera (or their
+indices, with 0 being the first one), and options are chosen from among those
+listed below. If the correct answer is a number, it is interpretted as an
+index, even if the array of choices are also numbers. (See the C below
+for more details.)
+
+The entries in the choices array can either be strings that are the text to use
+for the choice buttons, or C<< { label => text } >> where C