Skip to content

Commit d7f0584

Browse files
committed
Add PG critic to the PG problem editor.
This adds the PG critic results from `WeBWorK::PG::Critic` to the PG problem editor. Note that the "Format Code" tab in the editor is now the "Code Maintenance" tab. This is because this new option is not a code formatter. All of the options fit into the category of code maintenance, so this is a better name.
1 parent 1f5664c commit d7f0584

File tree

7 files changed

+138
-203
lines changed

7 files changed

+138
-203
lines changed

bin/check_modules.pl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ =head1 DESCRIPTION
8888
Net::OAuth
8989
Opcode
9090
Pandoc
91+
Perl::Critic
9192
Perl::Tidy
9293
PHP::Serialization
9394
Pod::Simple::Search

htdocs/js/PGProblemEditor/pgproblemeditor.js

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@
161161
?.addEventListener('change', () => (deleteBackupCheck.checked = true));
162162
}
163163

164+
const renderArea = document.getElementById('pgedit-render-area');
165+
166+
const scrollToRenderArea = () => {
167+
// Scroll to the top of the render window if the current scroll position is below that.
168+
const renderAreaRect = renderArea.getBoundingClientRect();
169+
const topBarHeight = document.querySelector('.webwork-logo')?.getBoundingClientRect().height ?? 0;
170+
if (renderAreaRect.top < topBarHeight) window.scrollBy(0, renderAreaRect.top - topBarHeight);
171+
};
172+
164173
// Send a request to the server to perltidy the current PG code in the CodeMirror editor.
165174
const tidyPGCode = () => {
166175
const request_object = { courseID: document.getElementsByName('courseID')[0]?.value };
@@ -251,24 +260,26 @@
251260
fetch(webserviceURL, { method: 'post', mode: 'same-origin', body: new URLSearchParams(request_object) })
252261
.then((response) => response.json())
253262
.then((data) => {
263+
if (data.error) throw new Error(data.error);
264+
if (!data.result_data) throw new Error('An invalid response was received.');
254265
renderArea.innerHTML = data.result_data.html;
266+
scrollToRenderArea();
255267
})
256-
.catch((err) => {
257-
console.log(err);
258-
showMessage(`Error: ${err?.message ?? err}`);
259-
});
268+
.catch((err) => showMessage(`Error: ${err?.message ?? err}`));
260269
};
261270

262271
document.getElementById('take_action')?.addEventListener('click', async (e) => {
263-
if (document.getElementById('current_action')?.value === 'format_code') {
272+
if (document.getElementById('current_action')?.value === 'code_maintenance') {
264273
e.preventDefault();
265-
if (document.querySelector('input[name="action.format_code"]:checked').value == 'tidyPGCode') {
274+
if (document.querySelector('input[name="action.code_maintenance"]:checked').value === 'tidyPGCode') {
266275
tidyPGCode();
267276
} else if (
268-
document.querySelector('input[name="action.format_code"]:checked').value == 'convertCodeToPGML'
277+
document.querySelector('input[name="action.code_maintenance"]:checked').value === 'convertCodeToPGML'
269278
) {
270279
convertCodeToPGML();
271-
} else if (document.querySelector('input[name="action.format_code"]:checked').value == 'runPGCritic') {
280+
} else if (
281+
document.querySelector('input[name="action.code_maintenance"]:checked').value === 'runPGCritic'
282+
) {
272283
runPGCritic();
273284
}
274285
return;
@@ -332,7 +343,6 @@
332343
});
333344

334345
const renderURL = `${webworkConfig?.webwork_url ?? '/webwork2'}/render_rpc`;
335-
const renderArea = document.getElementById('pgedit-render-area');
336346
const fileType = document.getElementsByName('file_type')[0]?.value;
337347

338348
// This is either the div containing the CodeMirror editor or the problemContents textarea in the case that
@@ -416,11 +426,7 @@
416426
}
417427

418428
adjustIFrameHeight();
419-
420-
// Scroll to the top of the render window if the current scroll position is below that.
421-
const renderAreaRect = renderArea.getBoundingClientRect();
422-
const topBarHeight = document.querySelector('.webwork-logo')?.getBoundingClientRect().height ?? 0;
423-
if (renderAreaRect.top < topBarHeight) window.scrollBy(0, renderAreaRect.top - topBarHeight);
429+
scrollToRenderArea();
424430
});
425431

426432
const render = () =>

lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ the submit button pressed (the action).
9090
Requested actions and aliases
9191
View/Reload action = view
9292
Generate Hardcopy: action = hardcopy
93-
Format Code: action = format_code
93+
Code Maintenance: action = code_maintenance
9494
Save: action = save
9595
Save as: action = save_as
9696
Append: action = add_problem
@@ -118,15 +118,15 @@ use SampleProblemParser qw(getSampleProblemCode generateMetadata);
118118
use constant DEFAULT_SEED => 123456;
119119

120120
# Editor tabs
121-
use constant ACTION_FORMS => [qw(view hardcopy format_code save save_as add_problem revert)];
121+
use constant ACTION_FORMS => [qw(view hardcopy code_maintenance save save_as add_problem revert)];
122122
use constant ACTION_FORM_TITLES => {
123-
view => x('View/Reload'),
124-
hardcopy => x('Generate Hardcopy'),
125-
format_code => x('Format Code'),
126-
save => x('Save'),
127-
save_as => x('Save As'),
128-
add_problem => x('Append'),
129-
revert => x('Revert'),
123+
view => x('View/Reload'),
124+
hardcopy => x('Generate Hardcopy'),
125+
code_maintenance => x('Code Maintenance'),
126+
save => x('Save'),
127+
save_as => x('Save As'),
128+
add_problem => x('Append'),
129+
revert => x('Revert'),
130130
};
131131

132132
my $BLANKPROBLEM = 'newProblem.pg';
@@ -847,9 +847,9 @@ sub view_handler ($c) {
847847
return;
848848
}
849849

850-
# The format_code action is handled by javascript. This is provided just in case
850+
# The code_maintenance action is handled by javascript. This is provided just in case
851851
# something goes wrong and the handler is called.
852-
sub format_code_handler { }
852+
sub code_maintenance_handler { }
853853

854854
sub hardcopy_handler ($c) {
855855
# Redirect to problem editor page.

lib/WebworkWebservice/ProblemActions.pm

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use warnings;
66

77
use Data::Structure::Util qw(unbless);
88

9-
use WeBWorK::PG::Tidy qw(pgtidy);
10-
use WeBWorK::PG::ConvertToPGML qw(convertToPGML);
11-
use WeBWorK::PG::PGProblemCritic qw(analyzePGcode);
9+
use WeBWorK::PG::Tidy qw(pgtidy);
10+
use WeBWorK::PG::ConvertToPGML qw(convertToPGML);
11+
use WeBWorK::PG::Critic qw(critiquePGCode);
1212

1313
sub getUserProblem {
1414
my ($invocant, $self, $params) = @_;
@@ -168,16 +168,13 @@ sub convertCodeToPGML {
168168

169169
sub runPGCritic {
170170
my ($invocant, $self, $params) = @_;
171-
my $pg_critic_results = analyzePGcode($params->{pgCode});
172-
173-
my $html_output = $self->c->render_to_string(
174-
template => 'ContentGenerator/Instructor/PGProblemEditor/pg_critic',
175-
results => $pg_critic_results
176-
);
177171

178172
return {
179173
ra_out => {
180-
html => $html_output
174+
html => $self->c->render_to_string(
175+
template => 'ContentGenerator/Instructor/PGProblemEditor/pg_critic',
176+
results => [ critiquePGCode($params->{pgCode}) ]
177+
)
181178
},
182179
text => 'The script pg-critic has been run successfully.'
183180
};

templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep renamed to templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
% last unless $c->{is_pg};
22
<div>
33
<div class="form-check">
4-
<%= radio_button 'action.format_code' => 'tidyPGCode',
5-
id => 'action_format_code_perltidy', class => 'form-check-input', checked => undef =%>
6-
<%= label_for 'action_format_code_perltidy', class => 'form-check-label', begin =%>
4+
<%= radio_button 'action.code_maintenance' => 'tidyPGCode',
5+
id => 'action_code_maintenance_perltidy', class => 'form-check-input', checked => undef =%>
6+
<%= label_for 'action_code_maintenance_perltidy', class => 'form-check-label', begin =%>
77
<%== maketext('Reformat the code using perltidy.') =%>
88
<% end =%>
99
<a class="help-popup" data-bs-content="<%== maketext('Perltidy is a reformatting '
@@ -15,31 +15,31 @@
1515
</a>
1616
</div>
1717
<div class="form-check">
18-
<%= radio_button 'action.format_code' => 'convertCodeToPGML',
19-
id => 'action_format_code_convert_PGML', class => 'form-check-input'=%>
20-
<%= label_for 'action_format_code_convert_PGML', class => 'form-check-label', begin =%>
18+
<%= radio_button 'action.code_maintenance' => 'convertCodeToPGML',
19+
id => 'action_code_maintenance_convert_PGML', class => 'form-check-input'=%>
20+
<%= label_for 'action_code_maintenance_convert_PGML', class => 'form-check-label', begin =%>
2121
<%== maketext('Convert the code to PGML') =%>
2222
<% end =%>
2323
<a class="help-popup" data-bs-content="<%== maketext('This option converts the text blocks '
2424
. 'in the problem code to PGML and updates the loadMacros to include PGML and drop others. '
2525
. 'This can be used as a first pass of the conversion, however the author will still need '
2626
. 'to ensure the problem functions. One area of attention should be the answer blanks, '
2727
. 'which may not be converted correctly.') =%>"
28-
data-bs-placement="top" data-bs-toggle="popover" role="button">
28+
data-bs-placement="top" data-bs-toggle="popover" role="button">
2929
<i aria-hidden="true" class="fas fa-question-circle"></i>
3030
<span class="visually-hidden"><%= maketext('PGML Conversion Help') %></span>
3131
</a>
3232
</div>
3333
<div class="form-check">
34-
<%= radio_button 'action.format_code' => 'runPGCritic',
35-
id => 'action_format_code_run_pgcritic', class => 'form-check-input'=%>
36-
<%= label_for 'action_format_code_run_pgcritic', class => 'form-check-label', begin =%>
34+
<%= radio_button 'action.code_maintenance' => 'runPGCritic',
35+
id => 'action_code_maintenance_run_pgcritic', class => 'form-check-input'=%>
36+
<%= label_for 'action_code_maintenance_run_pgcritic', class => 'form-check-label', begin =%>
3737
<%== maketext('Run the PG Critic Analyzer') =%>
3838
<% end =%>
3939
<a class="help-popup" data-bs-content="<%== maketext('This option runs the PG Critic '
40-
. 'code analyzer, which gives suggestions on using more modern PG constructs and '
41-
. 'ensure that you include important features. ') =%>"
42-
data-bs-placement="top" data-bs-toggle="popover" role="button">
40+
. 'code analyzer which gives suggestions on using modern PG constructs and '
41+
. 'ensures that you include important features.') =%>"
42+
data-bs-placement="top" data-bs-toggle="popover" role="button">
4343
<i aria-hidden="true" class="fas fa-question-circle"></i>
4444
<span class="visually-hidden"><%= maketext('PG Critic Help') %></span>
4545
</a>

0 commit comments

Comments
 (0)