diff --git a/htdocs/js/RenderProblem/renderproblem.js b/htdocs/js/RenderProblem/renderproblem.js index 726ff789a7..3041912cf1 100644 --- a/htdocs/js/RenderProblem/renderproblem.js +++ b/htdocs/js/RenderProblem/renderproblem.js @@ -28,7 +28,7 @@ send_pg_flags: 1, extra_header_text: '', ...renderOptions }; diff --git a/lib/FormatRenderedProblem.pm b/lib/FormatRenderedProblem.pm index 0b75d3538a..b3acd72e77 100644 --- a/lib/FormatRenderedProblem.pm +++ b/lib/FormatRenderedProblem.pm @@ -29,7 +29,6 @@ use Digest::SHA qw(sha1_base64); use Mojo::Util qw(xml_escape); use Mojo::DOM; -use WeBWorK::HTML::AttemptsTable; use WeBWorK::Utils qw(getAssetURL); use WeBWorK::Utils::LanguageAndDirection; @@ -145,23 +144,25 @@ sub formatRenderedProblem { my $showCorrectMode = defined($ws->{inputs_ref}{WWcorrectAns}) || 0; # A problemUUID should be added to the request as a parameter. It is used by PG to create a proper UUID for use in # aliases for resources. It should be unique for a course, user, set, problem, and version. - my $problemUUID = $ws->{inputs_ref}{problemUUID} // ''; - my $problemResult = $rh_result->{problem_result} // {}; - my $showSummary = $ws->{inputs_ref}{showSummary} // 1; - my $showAnswerNumbers = $ws->{inputs_ref}{showAnswerNumbers} // 1; - - # Attempts table - my $answerTemplate = ''; - - # Do not produce an AttemptsTable when we had a rendering error. - if (!$renderErrorOccurred && !$previewMode) { - $answerTemplate = WeBWorK::HTML::AttemptsTable->new( - $rh_result->{answers} // {}, $ws->c, - answersSubmitted => $ws->{inputs_ref}{answersSubmitted} // 0, - answerOrder => $rh_result->{flags}{ANSWER_ENTRY_ORDER} // [], - showSummary => (($showSummary && ($submitMode || $showCorrectMode)) // 0) ? 1 : 0, - summary => $problemResult->{summary} // '' # can be set by problem grader - )->answerTemplate; + my $problemUUID = $ws->{inputs_ref}{problemUUID} // ''; + my $problemResult = $rh_result->{problem_result} // {}; + my $showSummary = $ws->{inputs_ref}{showSummary} // 1; + + # Result summary + my $resultSummary = ''; + + my $lh = WeBWorK::Localize::getLangHandle($formLanguage); + + # Do not produce a result summary when we had a rendering error. + if (!$renderErrorOccurred && $showSummary && !$previewMode && ($submitMode || $showCorrectMode)) { + $resultSummary = $ws->c->c( + $ws->c->tag( + 'h2', + class => 'fs-3 mb-2', + $ws->c->maketext('Results for this submission') + ) + . $ws->c->tag('div', role => 'alert', $ws->c->b($problemResult->{summary})) + )->join(''); } # Answer hash in XML format used by the PTX format. @@ -204,7 +205,7 @@ sub formatRenderedProblem { $output->{input} = $ws->{input}; # The following could be constructed from the above, but this is a convenience - $output->{answerTemplate} = $answerTemplate->to_string if $answerTemplate; + $output->{resultSummary} = $resultSummary->to_string if $resultSummary; $output->{lang} = $PROBLEM_LANG_AND_DIR{lang}; $output->{dir} = $PROBLEM_LANG_AND_DIR{dir}; $output->{extra_css_files} = \@extra_css_files; @@ -232,7 +233,7 @@ sub formatRenderedProblem { formatName => $formatName, ws => $ws, ce => $ce, - lh => WeBWorK::Localize::getLangHandle($ws->{inputs_ref}{language} // 'en'), + lh => $lh, rh_result => $rh_result, SITE_URL => $SITE_URL, FORM_ACTION_URL => $SITE_URL . $ws->c->webwork_url . '/render_rpc', @@ -253,7 +254,7 @@ sub formatRenderedProblem { extra_js_files => \@extra_js_files, problemText => $problemText, extra_header_text => $ws->{inputs_ref}{extra_header_text} // '', - answerTemplate => $answerTemplate, + resultSummary => $resultSummary, showScoreSummary => $submitMode && !$renderErrorOccurred && $problemResult, answerhashXML => $answerhashXML, LTIGradeMessage => $LTIGradeMessage, @@ -265,9 +266,8 @@ sub formatRenderedProblem { isInstructor => $ws->{inputs_ref}{isInstructor} // '', forceScaffoldsOpen => $ws->{inputs_ref}{forceScaffoldsOpen} // '', showSummary => $showSummary, - showHints => $ws->{inputs_ref}{showHints} // '', - showSolutions => $ws->{inputs_ref}{showSolutions} // '', - showAnswerNumbers => $showAnswerNumbers, + showHints => $ws->{inputs_ref}{showHints} // '', + showSolutions => $ws->{inputs_ref}{showSolutions} // '', showPreviewButton => $ws->{inputs_ref}{showPreviewButton} // '', showCheckAnswersButton => $ws->{inputs_ref}{showCheckAnswersButton} // '', showCorrectAnswersButton => $ws->{inputs_ref}{showCorrectAnswersButton} // '', diff --git a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm index 0c67d26e9c..be343f8861 100644 --- a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm +++ b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm @@ -38,7 +38,6 @@ use WeBWorK::Utils::Tasks qw(fake_set fake_set_version fake_problem); use WeBWorK::Debug; use WeBWorK::Authen::LTIAdvanced::SubmitGrade; use WeBWorK::Authen::LTIAdvantage::SubmitGrade; -use WeBWorK::HTML::AttemptsTable; use PGrandom; use Caliper::Sensor; use Caliper::Entity; @@ -238,17 +237,8 @@ sub can_useMathQuill ($c) { } # Output utility -sub attemptResults ($c, $pg, $showSummary) { - my $ce = $c->ce; - - return WeBWorK::HTML::AttemptsTable->new( - $pg->{answers}, - $c, - answersSubmitted => 1, - answerOrder => $pg->{flags}{ANSWER_ENTRY_ORDER}, - showHeadline => 0, - showSummary => $showSummary, - )->answerTemplate; +sub attemptResults ($c, $pg) { + return $c->{can}{showProblemScores} ? $c->tag('div', role => 'alert', $c->b($pg->{result}{summary})) : ''; } sub get_instructor_comment ($c, $problem) { diff --git a/lib/WeBWorK/ContentGenerator/Problem.pm b/lib/WeBWorK/ContentGenerator/Problem.pm index 85aeb35dff..eb46b581f6 100644 --- a/lib/WeBWorK/ContentGenerator/Problem.pm +++ b/lib/WeBWorK/ContentGenerator/Problem.pm @@ -36,7 +36,6 @@ use WeBWorK::Localize; use WeBWorK::Utils::Tasks qw(fake_set fake_problem); use WeBWorK::Utils::LanguageAndDirection qw(get_problem_lang_and_dir); use WeBWorK::AchievementEvaluator; -use WeBWorK::HTML::AttemptsTable; # GET/POST Parameters for this module # @@ -246,16 +245,9 @@ sub can_showMeAnother ($c, $user, $effectiveUser, $set, $problem, $submitAnswers return 0; } -sub attemptResults ($c, $pg, $showSummary) { - my $ce = $c->ce; - - return WeBWorK::HTML::AttemptsTable->new( - $pg->{answers}, - $c, - answersSubmitted => 1, - answerOrder => $pg->{flags}{ANSWER_ENTRY_ORDER}, - showSummary => $showSummary, - )->answerTemplate; +sub attemptResults ($c, $pg) { + return $c->c($c->tag('h2', class => 'fs-3 mb-2', $c->maketext('Results for this submission')) + . $c->tag('div', role => 'alert', $c->b($pg->{result}{summary})))->join(''); } async sub pre_header_initialize ($c) { @@ -1469,7 +1461,7 @@ sub output_summary ($c) { # Attempt summary if ($c->{submitAnswers}) { - push(@$output, $c->attemptResults($pg, 1)); + push(@$output, $c->attemptResults($pg)); } elsif ($will{checkAnswers} || $c->{will}{showProblemGrader}) { push( @$output, @@ -1478,7 +1470,7 @@ sub output_summary ($c) { class => 'ResultsWithError d-inline-block mb-3', $c->maketext('ANSWERS ONLY CHECKED -- ANSWERS NOT RECORDED') ), - $c->attemptResults($pg, 1) + $c->attemptResults($pg) ); } elsif ($c->{previewAnswers}) { push( diff --git a/lib/WeBWorK/HTML/AttemptsTable.pm b/lib/WeBWorK/HTML/AttemptsTable.pm deleted file mode 100644 index 87065d28ef..0000000000 --- a/lib/WeBWorK/HTML/AttemptsTable.pm +++ /dev/null @@ -1,266 +0,0 @@ -################################################################################ -# WeBWorK Online Homework Delivery System -# Copyright © 2000-2023 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 - - AttemptsTable - -=head1 SYNPOSIS - - my $tbl = WeBWorK::HTML::AttemptsTable->new( - $answers, - answersSubmitted => 1, - answerOrder => $pg->{flags}{ANSWER_ENTRY_ORDER}, - showSummary => $showSummary, - maketext => WeBWorK::Localize::getLoc("en"), - ); - my $answerTemplate = $tbl->answerTemplate; - - -=head1 DESCRIPTION - -This module handles the formatting of the table which presents the results of analyzing a student's -answer to a WeBWorK problem. It is used in Problem.pm, OpaqueServer.pm, standAlonePGproblemRender - -=head2 new - - my $tbl = WeBWorK::HTML::AttemptsTable->new( - $answers, - answersSubmitted => 1, - answerOrder => $pg->{flags}{ANSWER_ENTRY_ORDER}, - showHeadline => 1, - showSummary => $showSummary, - maketext => WeBWorK::Localize::getLoc("en"), - summary =>'', - ); - - $answers -- a hash of student answers e.g. $pg->{answers} - answersSubmitted if 0 then then the attemptsTable is not displayed (???) - answerOrder -- an array indicating the order the answers appear on the page. - - showHeadline Show the header line 'Results for this submission' - - summary is obtained from $pg->{result}{summary}. - If this is empty then a (localized) - version of "all answers are correct" - or "at least one answer is not coorrect" - maketext points to a localization subroutine - -=head2 Methods - -=over 4 - -=item answerTemplate - -Returns HTML which formats the analysis of the student's answers to the problem. - -=back - -=head2 Read/Write Properties - -=over 4 - -=item summary - -The contents of the summary can be defined when the attemptsTable object is created. - -The summary can be defined by the PG problem grader usually returned as -$pg->{result}{summary}. - -If the summary is not explicitly defined then (localized) versions -of the default summaries are created: - - "The answer above is correct.", - "Some answers will be graded later.", - "All of the [gradeable] answers above are correct.", - "[N] of the questions remain unanswered.", - "At least one of the answers above is NOT [fully] correct.', - -Note that if this is set after initialization, you must ensure that it is a -Mojo::ByteStream object if it contains html or characters that need escaping. - -=back - -=cut - -package WeBWorK::HTML::AttemptsTable; -use Mojo::Base 'Class::Accessor', -signatures; - -use Scalar::Util 'blessed'; -use WeBWorK::Utils 'wwRound'; - -sub new ($class, $rh_answers, $c, %options) { - die 'The first entry to AttemptsTable must be a hash of answers' unless ref($rh_answers) =~ /HASH/; - die 'The second entry to AttemptsTable must be a WeBWorK::Controller' unless $c->isa('WeBWorK::Controller'); - - my $self = bless { - answers => $rh_answers, - c => $c, - answerOrder => $options{answerOrder} // [], - answersSubmitted => $options{answersSubmitted} // 0, - summary => undef, # summary provided by problem grader (set below) - showHeadline => $options{showHeadline} // 1, - showSummary => $options{showSummary} // 1, # show result summary - submitted => $options{submitted} // 0, - }, - ref $class || $class; - - # Create accessors/mutators - $self->mk_ro_accessors(qw(answers c answerOrder answersSubmitted showHeadline showSummary)); - $self->mk_accessors(qw(summary)); - - # Only show message column if there is at least one message. - my @reallyShowMessages = grep { $self->answers->{$_}{ans_message} } @{ $self->answerOrder }; - - # Make sure that the provided summary is a Mojo::ByteStream object. - $self->summary(blessed($options{summary}) - && $options{summary}->isa('Mojo::ByteStream') ? $options{summary} : $self->c->b($options{summary} // '')); - - return $self; -} - -# Determine whether any answers were submitted and create answer template if they have been. -sub answerTemplate ($self) { - my $c = $self->c; - - return '' unless $self->answersSubmitted; # Only print if answers were submitted. - - return $c->c( - $self->showHeadline - ? $c->tag('h2', class => 'attemptResultsHeader', $c->maketext('Results for this submission')) - : '', - $self->showSummary ? $self->createSummary : '' - )->join(''); -} - -# Create summary -sub createSummary ($self) { - my $c = $self->c; - - my $summary; - - unless (defined($self->summary) && $self->summary =~ /\S/) { - my $numCorrect = 0; - my $numBlank = 0; - my $numEssay = 0; - - for (@{ $self->answerOrder() }) { - my $answerScore = $self->{answers}{$_}{score} // 0; - my $isEssay = ($self->{answers}{$_}{type} // '') eq 'essay'; - ++$numCorrect if $answerScore >= 1; - ++$numEssay if $isEssay; - ++$numBlank unless $isEssay || ($self->{answers}{$_}{student_ans} // '') =~ /\S/ || $answerScore >= 1; - } - - # Default messages - $summary = $c->c; - my @answerNames = @{ $self->answerOrder() }; - if (@answerNames == 1) { - if ($numCorrect == 1) { - push( - @$summary, - $c->tag( - 'div', - class => 'ResultsWithoutError mb-2', - $c->maketext('The answer is correct.') - ) - ); - } elsif ($numEssay) { - push( - @$summary, - $c->tag( - 'div', - class => 'ResultsAlert mb-2', - $c->maketext('The answer will be graded later.') - ) - ); - } else { - push( - @$summary, - $c->tag( - 'div', - class => 'ResultsWithError mb-2', - $c->maketext('The answer is NOT correct.') - ) - ); - } - } else { - if ($numCorrect + $numEssay == @answerNames) { - if ($numEssay) { - push( - @$summary, - $c->tag( - 'div', - class => 'ResultsWithoutError mb-2', - $c->maketext('All of the gradeable answers are correct.') - ) - ); - } else { - push( - @$summary, - $c->tag( - 'div', - class => 'ResultsWithoutError mb-2', - $c->maketext('All of the answers are correct.') - ) - ); - } - } elsif ($numBlank + $numEssay + $numCorrect != @answerNames) { - push( - @$summary, - $c->tag( - 'div', - class => 'ResultsWithError mb-2', - $c->maketext( - '[_1] of the answers [plural,_1,is,are] NOT correct.', - @answerNames - $numBlank - $numCorrect - $numEssay - ) - ) - ); - } - if ($numBlank) { - push( - @$summary, - $c->tag( - 'div', - class => 'ResultsAlert mb-2', - $c->maketext( - '[quant,_1,of the questions remains,of the questions remain] unanswered.', $numBlank - ) - ) - ); - } - if ($numEssay) { - push( - @$summary, - $c->tag( - 'div', - class => 'ResultsAlert mb-2', - $c->maketext('[_1] of the answers will be graded later.', $numEssay) - ) - ); - } - } - $summary = $summary->join(''); - } else { - $summary = $self->summary; # Summary defined by grader - } - - $summary = $c->tag('div', role => 'alert', class => 'attemptResultsSummary', $summary); - $self->summary($summary); - return $summary; -} - -1; diff --git a/templates/ContentGenerator/GatewayQuiz.html.ep b/templates/ContentGenerator/GatewayQuiz.html.ep index 6e317de15d..35d51004b1 100644 --- a/templates/ContentGenerator/GatewayQuiz.html.ep +++ b/templates/ContentGenerator/GatewayQuiz.html.ep @@ -490,7 +490,6 @@ <%= $jumpLinks->() =%> % % # Print out problems and attempt results, as appropriate. - % # Note: Usage is $c->attemptResults($pg, $showSummary) % for my $i (0 .. $#$pg_results) { % my $pg = $pg_results->[ $probOrder->[$i] ]; % @@ -504,13 +503,13 @@ % maketext('ANSWERS NOT RECORDED -- [_1]', $c->{scoreRecordedMessage}[ $probOrder->[$i] ]) % ); % } - % $resultsTable = $c->attemptResults($pg, $c->{can}{showProblemScores}); + % $resultsTable = $c->attemptResults($pg); % } elsif ($c->{will}{checkAnswers} || $c->{will}{showProblemGrader}) { % $recordMessage = tag('div', class => 'ResultsWithError d-inline-block mb-2', % maketext('ANSWERS ONLY CHECKED -- ANSWERS NOT RECORDED') % ); % - % $resultsTable = $c->attemptResults($pg, $c->{can}{showProblemScores}); + % $resultsTable = $c->attemptResults($pg); % } elsif ($c->{previewAnswers}) { % $recordMessage = tag('div', class => 'ResultsWithError d-inline-block mb-2', % maketext('PREVIEW ONLY -- ANSWERS NOT RECORDED') diff --git a/templates/RPCRenderFormats/default.html.ep b/templates/RPCRenderFormats/default.html.ep index fbccee5544..71e4f68543 100644 --- a/templates/RPCRenderFormats/default.html.ep +++ b/templates/RPCRenderFormats/default.html.ep @@ -37,7 +37,7 @@
- %== $answerTemplate + %== $resultSummary <%= form_for $FORM_ACTION_URL, id => 'problemMainForm', class => 'problem-main-form', name => 'problemMainForm', method => 'POST', begin %>
> @@ -66,7 +66,6 @@ % } %== $LTIGradeMessage % - %= hidden_field answersSubmitted => 1 %= hidden_field sourceFilePath => $sourceFilePath %= hidden_field problemSource => $problemSource %= hidden_field uriEncodedProblemSource => $uriEncodedProblemSource @@ -87,7 +86,6 @@ %= hidden_field showSummary => $showSummary %= hidden_field showHints => $showHints %= hidden_field showSolutions => $showSolutions - %= hidden_field showAnswerNumbers => $showAnswerNumbers %= hidden_field showPreviewButton => $showPreviewButton %= hidden_field showCheckAnswersButton => $showCheckAnswersButton %= hidden_field showCorrectAnswersButton => $showCorrectAnswersButton diff --git a/templates/RPCRenderFormats/default.json.ep b/templates/RPCRenderFormats/default.json.ep index 38a8c504d9..c25764aadd 100644 --- a/templates/RPCRenderFormats/default.json.ep +++ b/templates/RPCRenderFormats/default.json.ep @@ -19,7 +19,7 @@ % % body_part001 => '', % body_part100 => '
', - % body_part300 => $answerTemplate, + % body_part300 => $resultSummary, % body_part500 => '
', % body_part530 => qq{
}, @@ -46,7 +46,6 @@ % . '}', % % hidden_input_field => { - % answersSubmitted => '1', % sourceFilePath => $sourceFilePath, % problemSource => $problemSource, % problemSeed => $problemSeed, @@ -64,7 +63,6 @@ % showSummary => $showSummary, % showHints => $showHints, % showSolutions => $showSolutions, - % showAnswerNumbers => $showAnswerNumbers, % showPreviewButton => $showPreviewButton, % showCheckAnswersButton => $showCheckAnswersButton, % showCorrectAnswersButton => $showCorrectAnswersButton,