Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new context flag to require constant entries #990

Merged
merged 2 commits into from
Feb 14, 2024

Conversation

Alex-Jordan
Copy link
Contributor

This makes it so that you can set a context flag requireConstantEntries, and if so, vectors cannot have variables in their entries. But for example something like t <1, 2, 3> is still legal. This allows me to write a problem that requires students to "factor out" a parameter from vector answers.

I want to check with @dpvc that this is an OK way to do this. If so I will extend this PR to do the same thing for Matrix objects. And I'll add a default value of 0 to Default.pm.

@pstaabp
Copy link
Member

pstaabp commented Jan 24, 2024

@Alex-Jordan Can you show an example problem that would use this?

@Alex-Jordan
Copy link
Contributor Author

Here is a problem that uses this. For example, the answer might be r<3,1,1,0> + s<1,-3,0,1>. It will not accept <3r+s,r-3s,r,s>. If you try that, it returns "Coordinates of Vectors must be constant".

# WeBWorK problem written by Alex Jordan 
DOCUMENT();

loadMacros(qw(
    PGstandard.pl PGML.pl PCCmacros.pl
));

Context("Matrix")->flags->set(requireConstantEntries => 1);
Context()->variables->are(
    r => 'Real',
    s => 'Real',
    t => 'Real',
    a => 'Real',
    b => 'Real',
    c => 'Real',
);

$a1 = ColumnVector(random(1,3), 0);
$a2 = ColumnVector(random(-7,-3), random(-9,-2));

$h = non_zero_random(-4,5);
$k = non_zero_random(-4,5);
$a3 = $h*$a1 + $k*$a2;
$g3 = gcd($a3->value);
$a3 = $a3/$g3;

$i = non_zero_random(-3,3);
$j = non_zero_random(-3,3);
$a4 = $i*$a1 + $j*$a2;
$g4 = gcd($a4->value);
$a4 = $a4/$g4;

$b = ColumnVector(0,0);

$x1 = ColumnVector(-$h,-$k,$g3,0);
$x2 = ColumnVector(-$i,-$j,0,$g4);

$A = Matrix($a1, $a2, $a3, $a4)->transpose;

$sol = Formula("r $x1 + s $x2");
$ans = $sol->cmp(checker => sub {
    my ($c,$s,$self) = @_;
    $s = Formula("$s")->reduce;
    Value::Error("Your answer does not solve the system.") unless ($A*$s == Matrix($b)->transpose);
    # How many parameters did student use?
    $spar = $s->usesOneOf('r') + $s->usesOneOf('s') + $s->usesOneOf('t') + $s->usesOneOf('a') + $s->usesOneOf('b') + $s->usesOneOf('c');
    Value::Error("Your answer uses more parameters than is necessary.") if ($spar > 2);
    Value::Error("Your answer does not use enough parameters.") if ($spar < 2);
    # Get dimension of span of student answer space
    @svec = map {$s->eval(r => random(1,9), s => random(1,9), t => random(1,9), a => random(1,9), b => random(1,9), c => random(1,9))} (0..3);
    $sdim = Matrix(@svec)->order_LR;
    Value::Error("Your answer does not parametrize the entire solution set.") if ($sdim < 2);
    # Now we know student answer uses exactly the right number of parameters
    # and also not in some trivial way since the dimension is right
    return 1;
});

# remove the check for equivalency with previous submitted answer
pop(@{$ans->{post_filters}});

BEGIN_PGML
Describe all solutions to the matrix equation [`A\vec{x}=\vec{0}`] where [`A`] is row equivalent to [```[$A]```]
Write the solution set in parametric vector form.
[@ KeyboardInstructions('You may use [`r`], [`s`], [`t`], [`a`], [`b`], [`c`] as parameters, as needed.
Enter vectors using angle brackets. For example, to enter [`\begin{bmatrix}1\\\\2\end{bmatrix}`], type [|<1,2>|]*.') @]**

[`\vec{x}={}`][_]{$ans}

END_PGML

ENDDOCUMENT();

Copy link
Member

@dpvc dpvc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any problem with this, though I left a comment that should allow you to make it more efficient.

You may also want to consider a more specific flag name, like requireConstantVectorEntries if you are also planning to do this for Matrices, so that you can control them individually.

Comment on lines 25 to 27
if ($self->context->flag("requireConstantEntries") && !($x->{isConstant})) {
$self->{equation}->Error("Coordinates of Vectors must be constant");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to check each coordinate separately, as the vector's isConstant flag will already be set by the time the _check subroutine is called, so I think you can just do

	$self->{equation}->Error("Coordinates of Vectors must be constant");
	  if $self->context->flag("requireConstantEntries") && !($self->{isConstant};

after the foreach loop.

@pstaabp
Copy link
Member

pstaabp commented Jan 31, 2024

Testing your problem above, the correct answer was supposed to be: r<1,-1,3,0>+s<2,-3,0,3> and I entered <r,-r,3r,0>+s<2,-3,0,3> getting the incorrect answer. However, under the feedback, the entered answer was listed "+s<2,-3,0,3>". Seems to have dropped off the first term.

@Alex-Jordan
Copy link
Contributor Author

I also see the issue that @pstaabp found. And I see it after applying @dpvc 's suggestion too.

This calls $self->{equation}->Error() if there are non-constant entries in a vector. You can also trigger $self->{equation}->Error() a few lines above if the entries are not of type number, and when I do that, I do not see anything similar happen. That is, I don't see a portion of the parsed expression disappear. I'm not sure what to look into next.

@dpvc
Copy link
Member

dpvc commented Feb 5, 2024

Does the feedback mechanism properly escape HTML special characters like < and >? The <r,-r,3r,0> part of the answer might look like a custom tag, whereas <2,-3,0,3> does not because a tag name must start with a letter. I'm not able to run the current develop version of WW, so can't check this myself. But that's what it looks like might be happening to me.

@Alex-Jordan
Copy link
Contributor Author

So now I'm not able to reproduce the issue. I am wondering if what happened was Davide's suggested change actually did incidentally fix that issue, but while I was testing I forgot to restart webwork2. So it was still running off the old .pm. @pstaabp can you try this now?

If the same issue arises, can you look into Davide's idea? In the HTML source for the page, do you see the angle brackets?

@drgrice1
Copy link
Member

drgrice1 commented Feb 5, 2024

This is an issue with HTML characters. The DOM shows that the entire answer is there, but it is not rendered because of the starting < tag. This is only in the entered field, and not the preview. This is tricky because this is all an HTML encoded attribute value on a div. The decoding when the popover opens decodes everything into the DOM, and not just what is meant to be HTML. I will see what I can do about it.

@drgrice1
Copy link
Member

drgrice1 commented Feb 5, 2024

It is odd that this does not happen with the develop branch though. It only happens with this pull request. I haven't figured out why that is the case.

@Alex-Jordan
Copy link
Contributor Author

Well, I'm thoroughly confused and wondering if the behavior is not consistent. I know for sure that prior to my Feb 3 comment here, I tested this on both 2.18 (where I made a local uncommitted edit) and on develop. And I saw the issue both places (in the results table in 2.18 and in the popover with develop). I specifically confirmed that before I made that comment because I was wondering if the results table was a piece of the puzzle.

Earlier today on develop I could not repeat the issue, which made me think that in earlier testing I hadn't restarted webwork2. But now with what you (@drgrice1 ) say, I'm just really confused.

@Alex-Jordan
Copy link
Contributor Author

Oh! I get it...

In my testing today, the answer I tried was <-r,r,r,0>+ whatever. The dash character after the < probably saves me from the tag interpretation. But when it is <r,r,r,0> or like @pstaabp 's example, the <r ... > looks like a tag to the web browser.

So is this issue actually independent of this PR? Would any vector that starts with a letter after the < have this presentation issue?

@drgrice1
Copy link
Member

drgrice1 commented Feb 6, 2024

I am able to get this to happen on develop as well. I just had to get an error to occur in the student answer (but not the one from this pull request). Testing this with 2.18 and the attempts table, I see that this also happens there. So this is not an issue with this pull request, and is also not an issue with the new feedback mechanism.

The issue is that student_ans is coming in already escaped when errors do not occur. However, when an error occurs, then it is not escaped. I am working on tracking down why that is, but the issue is an inconsistency in how PG is setting the student_ans in the answer hash.

@Alex-Jordan
Copy link
Contributor Author

A note to anyone who might look at this PR: I will extend this to Matrices and Points, and do as Davide suggested and use different flag names for each. So this can wait for a new review until I add those. And the bug @pstaabp found is an independent issue that Glenn has a handle on.

@drgrice1
Copy link
Member

drgrice1 commented Feb 6, 2024

Testing this in a script from the command line, if the input for the answer has the value <1,0,0> then the value of student_ans in the answer hash is &lt;1,0,0&gt;, and if the input has the value <s(1,0),0,0> then student_ans is <s(1,0),0,0>.

I also tested this with webwork and pg version 2.17, and this issue already occurred with that version. So this isn't an issue with the Mojolicious change either.

drgrice1 added a commit to drgrice1/pg that referenced this pull request Feb 6, 2024
…s occur.

This addresses the issue found in openwebwork#990.  This issue occurs at least as
far back as PG 2.17 (but probably occured before that as well.

If an answer has an error that prevents it from being parsed into a
MathObject value, and yet the error `pos` is not set, then the answer is
not HTML escaped as it should be.  This can result in the answer in the
"You Entered" feedback entry (or the old attempts table "Entered"
column) not being displayed correctly.

You can test with the problem
```perl
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix');
$v = Vector(1, 0, 0);

BEGIN_PGML
Enter the vector [`[$v]`]: [_]{$v}
END_PGML

ENDDOCUMENT();
```

If you enter the answer `<x(1,0),0,0>`, then on the develop branch the
"You Entered" section of feedback will appear to be empty.  Using the
element inspector of the developer tools you will see that it is there.
With this pull request it will appear as it should.

Note that in the cases that the answer does parse into a MatHObject
value or the error `pos` is set, then the answer is HTML escaped
already.
drgrice1 added a commit to drgrice1/pg that referenced this pull request Feb 6, 2024
…s occur.

This addresses the issue found in openwebwork#990.  This issue occurs at least as
far back as PG 2.17 (but probably occured before that as well).

If an answer has an error that prevents it from being parsed into a
MathObject value, and yet the error `pos` is not set, then the answer is
not HTML escaped as it should be.  This can result in the answer in the
"You Entered" feedback entry (or the old attempts table "Entered"
column) not being displayed correctly.

You can test with the problem
```perl
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix');
$v = Vector(1, 0, 0);

BEGIN_PGML
Enter the vector [`[$v]`]: [_]{$v}
END_PGML

ENDDOCUMENT();
```

If you enter the answer `<x(1,0),0,0>`, then on the develop branch the
"You Entered" section of feedback will appear to be empty.  Using the
element inspector of the developer tools you will see that it is there.
With this pull request it will appear as it should.

Note that in the cases that the answer does parse into a MatHObject
value or the error `pos` is set, then the answer is HTML escaped
already.
@dpvc
Copy link
Member

dpvc commented Feb 6, 2024

One of the sources of this problem is that it is not clear what student_ans should contain; is it HTML, LaTeX, text, or different things under different circumstances? Because the student_ans shows in the results table (or used to), it was used to highlight the error location in the student answer, and so included HTML to do that, so it had to be considered escaped HTML for that purpose. But that means there is no plain-text version of the student answer. I've always thought there should be student_ans_text, student_ans_html, student_ans_latex, and similarly correct_ans_text, preview_ans_text, and so on. But straightening that all out in all the macros that set one or another of these would be quite an undertaking, I would think.

@Alex-Jordan
Copy link
Contributor Author

This now has three new flags: requireConstantPoints, requireConstantVectors, requireConstantMatrices.

Note that a Point, Vector, or Matrix object would be required to have constant entries, including when used in a Formula. But a Formula that returns Points, Vectors, or Matrices is not necessarily required to be constant. For example, Formula("x <1,2>") is a Formula that returns vectors, and is fine to use when requireConstantVectors is set.

So I considered having more clear names for these flags, to make it more clear that the entries need to be constant but nothing is required outside of the object: requireConstantPointEntries, requireConstantVectorEntries, requireConstantMatrixEntries. Is it worth the added verbosity?

Whenever this is resolved and merged, I need to update wiki documentation or I'm pretty sure documentation for this will be forgotten about later.

Alex-Jordan pushed a commit to Alex-Jordan/pg that referenced this pull request Feb 13, 2024
…s occur.

This addresses the issue found in openwebwork#990.  This issue occurs at least as
far back as PG 2.17 (but probably occured before that as well).

If an answer has an error that prevents it from being parsed into a
MathObject value, and yet the error `pos` is not set, then the answer is
not HTML escaped as it should be.  This can result in the answer in the
"You Entered" feedback entry (or the old attempts table "Entered"
column) not being displayed correctly.

You can test with the problem
```perl
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix');
$v = Vector(1, 0, 0);

BEGIN_PGML
Enter the vector [`[$v]`]: [_]{$v}
END_PGML

ENDDOCUMENT();
```

If you enter the answer `<x(1,0),0,0>`, then on the develop branch the
"You Entered" section of feedback will appear to be empty.  Using the
element inspector of the developer tools you will see that it is there.
With this pull request it will appear as it should.

Note that in the cases that the answer does parse into a MatHObject
value or the error `pos` is set, then the answer is HTML escaped
already.
@Alex-Jordan Alex-Jordan requested a review from dpvc February 13, 2024 07:43
@Alex-Jordan
Copy link
Contributor Author

@dpvc This still has a block on it that you set. I think that the issue that floated up here has been determined to be an independent issue. Do you think what is there now looks good, at least as far as the scope of this PR?

@pstaabp
Copy link
Member

pstaabp commented Feb 13, 2024

This looks good now. Tested both constant vectors and constant points. Although it make sense to use constantMatrix as well, I'm trying to figure out how to test. Since the standard is to use a matrix input, there wouldn't be a way to have a variable times that. @Alex-Jordan do you have an idea about using this?

@drgrice1
Copy link
Member

@pstaabp: Matrices can also be asked to be entered in a single text input in the format [[1,0],[0,1]] (for example). In that case you can give scalar multiples. For example, one could enter s[[1,0],[0,0]]+t[[0,0],[0,1]].

@drgrice1
Copy link
Member

By the way, here is a very simple example of how to ask for a matrix in the format I mentioned (not utilizing the new flag):

DOCUMENT();

loadMacros('PGstandard.pl', 'MathObjects.pl', 'PGML.pl');

Context('Matrix');
$matrix1 = Matrix('[[1,0],[0,1]]');

BEGIN_PGML
What is the [`2 \times 2`] identity matrix?

[_]{$matrix1}{10}
END_PGML

ENDDOCUMENT();

@drgrice1
Copy link
Member

Actually, something doesn't seem to be working with the matrix flag. With the following example:

DOCUMENT();

loadMacros('PGstandard.pl', 'MathObjects.pl', 'PGML.pl');

Context('Matrix')->flags->set(requireConstantMatrices => 1);
Context()->variables->are(s => 'Real', t => 'Real');
$matrix = Matrix('s[[1,0],[0,0]] + t[[0,0],[0,1]]');

BEGIN_PGML
Enter the matrix [`[$matrix]`]:

[_]{$matrix}{10}
END_PGML

ENDDOCUMENT();

I can enter [[s,0],[0,t]] and it is counted correct. Am I missing something?

@drgrice1
Copy link
Member

drgrice1 commented Feb 14, 2024

Nevermind. It turns out you need to check out this pull request for the flag to work.

@drgrice1 drgrice1 merged commit b3f45a5 into openwebwork:develop Feb 14, 2024
2 checks passed
drgrice1 added a commit to drgrice1/pg that referenced this pull request Feb 29, 2024
This backs up one step from what was done in openwebwork#1004.  Instead of calling
`protectHTML` on `$ans->{student_ans}` in the `cmp_error` method, that
is instead called in the `cmp_parse` method in the case that the
`$ans->{student_value}` is undefined.

With openwebwork#1004, if `student_value` was defined, and then a problem author
calls `Value::Error` in a custom answer checker, it results in the
`student_ans` being escaped twice because it is escaped in `cmp_parse`
and then again after the custom answer checker is called.  With this
approach the `student_ans` is escaped when `cmp_parse` is called in
either case regardless if if `student_value` is definece, and then not
again later (if `student_value` is defined and thus the checker is
called)

This is also before the `format_matrix` method is called for array
answers.  This fixes an issue also caused by escaping those already HTML
formatted answers. In that case the `student_ans` is completely
redefined after this from the `student_formula`.  With openwebwork#1004, the
`student_ans` is first HTML formatted in this case, and then later
escaped which results in an incorrect display.

This of course still fixes the issue that openwebwork#1004 attempted to fix,
because the `student_value` is not defined, and so the `protectHTML` now
called in `cmp_parse` covers this case.

I am sure that this is not the end of this issue, but is better than
both before openwebwork#1004 and after.  I think that something along the lines of
@dpvc's suggestion in
openwebwork#990 (comment) will
be needed to fully resolve this issue.  I suggest that rather than
having `student_ans_text`, `student_ans_html`, `student_ans_latex`, and
`preview_ans_text` as suggested there, we use `student_ans`,
`preview_latex_string`, and `preview_text_string`.  `student_ans` would
always remain a text answer, and never be HTML formatted,
`preview_ans_latex` would stay the same and be LaTeX, and
`preview_text_string` would always be HTML.  The naming is not the best
since `preview_text_string` is actually HTML, but it is the closest to
the current usage, and so would take the least work.  Note that
currently `preview_text_string` is not actually used for anything.  Even
though it is documented in `lib/AnswerHash.pm` as being what is supposed
to be displayed for the preview.  So this proposal just aligns that
answer hash key with its intended use.
drgrice1 added a commit to drgrice1/pg that referenced this pull request Feb 29, 2024
This backs up one step from what was done in openwebwork#1004.  Instead of calling
`protectHTML` on `$ans->{student_ans}` in the `cmp_error` method, that
is instead called in the `cmp_parse` method in the case that the
`$ans->{student_value}` is undefined.

With openwebwork#1004, if `student_value` was defined, and then a problem author
calls `Value::Error` in a custom answer checker, it results in the
`student_ans` being escaped twice because it is escaped in `cmp_parse`
and then again after the custom answer checker is called.  With this
approach the `student_ans` is escaped when `cmp_parse` is called in
either case regardless if if `student_value` is defined, and then not
again later (if `student_value` is defined and thus the checker is
called)

This is also before the `format_matrix` method is called for array
answers.  This fixes an issue also caused by escaping those already HTML
formatted answers. In that case the `student_ans` is completely
redefined after this from the `student_formula`.  With openwebwork#1004, the
`student_ans` is first HTML formatted in this case, and then later
escaped which results in an incorrect display.

This of course still fixes the issue that openwebwork#1004 attempted to fix,
because the `student_value` is not defined, and so the `protectHTML` now
called in `cmp_parse` covers this case.

I am sure that this is not the end of this issue, but is better than
both before openwebwork#1004 and after.  I think that something along the lines of
@dpvc's suggestion in
openwebwork#990 (comment) will
be needed to fully resolve this issue.  I suggest that rather than
having `student_ans_text`, `student_ans_html`, `student_ans_latex`, and
`preview_ans_text` as suggested there, we use `student_ans`,
`preview_latex_string`, and `preview_text_string`.  `student_ans` would
always remain a text answer, and never be HTML formatted,
`preview_ans_latex` would stay the same and be LaTeX, and
`preview_text_string` would always be HTML.  The naming is not the best
since `preview_text_string` is actually HTML, but it is the closest to
the current usage, and so would take the least work.  Note that
currently `preview_text_string` is not actually used for anything.  Even
though it is documented in `lib/AnswerHash.pm` as being what is supposed
to be displayed for the preview.  So this proposal just aligns that
answer hash key with its intended use.

Test cases:

```
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix')->flags->set(requireConstantVectors => 1);
Context()->variables->are(s => 'Real', t => 'Real');

$ans     = Formula('s<1, 0> + t<0, 1>');
$ans_cmp = $ans->cmp(
    checker => sub {
        my ($c, $s, $self) = @_;
        Value::Error('Try again') unless $c == $s;
        return 1;
    }
);

BEGIN_PGML
Enter [`[$ans]`]: [_]{$ans_cmp}
END_PGML

ENDDOCUMENT();
```

With this problem enter `<s,0>+t<0,1>`.  Prior to openwebwork#1004 the first vector
would disappear from the displayed answer because `student_ans` was not
escaped. After openwebwork#1004 and still with this pull request this is displayed
correctly.

Also with this problem enter `s<1,0>+t<0,2>`.  Prior to openwebwork#1004 this
displayed correctly.  With openwebwork#1004 it is displayed as
`s*&lt;1,0&gt;+t*&lt;0,2&gt;`.  With this pull request is is displayed
correctly.

```
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix');
$A = Matrix([ [ 1, 0 ], [ 0, -1 ] ]);

BEGIN_PGML
Enter the matrix [`[$A]`]:

[_]*{$A}
END_PGML

ENDDOCUMENT();
```

With this problem enter `S, -1, 1, 0` for the matrix entries.  Prior
to openwebwork#1004 this displayed correctly.  With openwebwork#1004 this is escaped twice,
and so you see the HTML code displayed.  With this pull request this is
again displayed correctly.
drgrice1 added a commit to drgrice1/pg that referenced this pull request Feb 29, 2024
This backs up one step from what was done in openwebwork#1004.  Instead of calling
`protectHTML` on `$ans->{student_ans}` in the `cmp_error` method, that
is instead called in the `cmp_parse` method in the case that the
`$ans->{student_value}` is undefined.

With openwebwork#1004, if `student_value` was defined, and then a problem author
calls `Value::Error` in a custom answer checker, it results in the
`student_ans` being escaped twice because it is escaped in `cmp_parse`
and then again after the custom answer checker is called.  With this
approach the `student_ans` is escaped when `cmp_parse` is called in
either case regardless if if `student_value` is defined, and then not
again later (if `student_value` is defined and thus the checker is
called)

This is also before the `format_matrix` method is called for array
answers.  This fixes an issue also caused by escaping those already HTML
formatted answers. In that case the `student_ans` is completely
redefined after this from the `student_formula`.  With openwebwork#1004, the
`student_ans` is first HTML formatted in this case, and then later
escaped which results in an incorrect display.

This of course still fixes the issue that openwebwork#1004 attempted to fix,
because the `student_value` is not defined, and so the `protectHTML` now
called in `cmp_parse` covers this case.

I am sure that this is not the end of this issue, but is better than
both before openwebwork#1004 and after.  I think that something along the lines of
@dpvc's suggestion in
openwebwork#990 (comment) will
be needed to fully resolve this issue.  I suggest that rather than
having `student_ans_text`, `student_ans_html`, `student_ans_latex`, and
`preview_ans_text` as suggested there, we use `student_ans`,
`preview_latex_string`, and `preview_text_string`.  `student_ans` would
always remain a text answer, and never be HTML formatted,
`preview_ans_latex` would stay the same and be LaTeX, and
`preview_text_string` would always be HTML.  The naming is not the best
since `preview_text_string` is actually HTML, but it is the closest to
the current usage, and so would take the least work.  Note that
currently `preview_text_string` is not actually used for anything.  Even
though it is documented in `lib/AnswerHash.pm` as being what is supposed
to be displayed for the preview.  So this proposal just aligns that
answer hash key with its intended use.

Test cases:

```
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix')->flags->set(requireConstantVectors => 1);
Context()->variables->are(s => 'Real', t => 'Real');

$ans     = Formula('s<1, 0> + t<0, 1>');
$ans_cmp = $ans->cmp(
    checker => sub {
        my ($c, $s, $self) = @_;
        Value::Error('Try again') unless $c == $s;
        return 1;
    }
);

BEGIN_PGML
Enter [`[$ans]`]: [_]{$ans_cmp}
END_PGML

ENDDOCUMENT();
```

With this problem enter `<s,0>+t<0,1>`.  Prior to openwebwork#1004 the first vector
would disappear from the displayed answer because `student_ans` was not
escaped. After openwebwork#1004 and still with this pull request this is displayed
correctly.

Also with this problem enter `s<1,0>+t<0,2>`.  Prior to openwebwork#1004 this
displayed correctly.  With openwebwork#1004 it is displayed as
`s*&lt;1,0&gt;+t*&lt;0,2&gt;`.  With this pull request is is displayed
correctly.

```
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix');
$A = Matrix([ [ 1, 0 ], [ 0, -1 ] ]);

BEGIN_PGML
Enter the matrix [`[$A]`]:

[_]*{$A}
END_PGML

ENDDOCUMENT();
```

With this problem enter `S, -1, 1, 0` for the matrix entries.  Prior
to openwebwork#1004 this displayed correctly.  With openwebwork#1004 this is escaped twice,
and so you see the HTML code displayed.  With this pull request this is
again displayed correctly.
drgrice1 added a commit to drgrice1/pg that referenced this pull request Mar 14, 2024
This backs up one step from what was done in openwebwork#1004.  Instead of calling
`protectHTML` on `$ans->{student_ans}` in the `cmp_error` method, that
is instead called in the `cmp_parse` method in the case that the
`$ans->{student_value}` is undefined.

With openwebwork#1004, if `student_value` was defined, and then a problem author
calls `Value::Error` in a custom answer checker, it results in the
`student_ans` being escaped twice because it is escaped in `cmp_parse`
and then again after the custom answer checker is called.  With this
approach the `student_ans` is escaped when `cmp_parse` is called in
either case regardless if if `student_value` is defined, and then not
again later (if `student_value` is defined and thus the checker is
called)

This is also before the `format_matrix` method is called for array
answers.  This fixes an issue also caused by escaping those already HTML
formatted answers. In that case the `student_ans` is completely
redefined after this from the `student_formula`.  With openwebwork#1004, the
`student_ans` is first HTML formatted in this case, and then later
escaped which results in an incorrect display.

This of course still fixes the issue that openwebwork#1004 attempted to fix,
because the `student_value` is not defined, and so the `protectHTML` now
called in `cmp_parse` covers this case.

I am sure that this is not the end of this issue, but is better than
both before openwebwork#1004 and after.  I think that something along the lines of
@dpvc's suggestion in
openwebwork#990 (comment) will
be needed to fully resolve this issue.  I suggest that rather than
having `student_ans_text`, `student_ans_html`, `student_ans_latex`, and
`preview_ans_text` as suggested there, we use `student_ans`,
`preview_latex_string`, and `preview_text_string`.  `student_ans` would
always remain a text answer, and never be HTML formatted,
`preview_ans_latex` would stay the same and be LaTeX, and
`preview_text_string` would always be HTML.  The naming is not the best
since `preview_text_string` is actually HTML, but it is the closest to
the current usage, and so would take the least work.  Note that
currently `preview_text_string` is not actually used for anything.  Even
though it is documented in `lib/AnswerHash.pm` as being what is supposed
to be displayed for the preview.  So this proposal just aligns that
answer hash key with its intended use.

Test cases:

```
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix')->flags->set(requireConstantVectors => 1);
Context()->variables->are(s => 'Real', t => 'Real');

$ans     = Formula('s<1, 0> + t<0, 1>');
$ans_cmp = $ans->cmp(
    checker => sub {
        my ($c, $s, $self) = @_;
        Value::Error('Try again') unless $c == $s;
        return 1;
    }
);

BEGIN_PGML
Enter [`[$ans]`]: [_]{$ans_cmp}
END_PGML

ENDDOCUMENT();
```

With this problem enter `<s,0>+t<0,1>`.  Prior to openwebwork#1004 the first vector
would disappear from the displayed answer because `student_ans` was not
escaped. After openwebwork#1004 and still with this pull request this is displayed
correctly.

Also with this problem enter `s<1,0>+t<0,2>`.  Prior to openwebwork#1004 this
displayed correctly.  With openwebwork#1004 it is displayed as
`s*&lt;1,0&gt;+t*&lt;0,2&gt;`.  With this pull request is is displayed
correctly.

```
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix');
$A = Matrix([ [ 1, 0 ], [ 0, -1 ] ]);

BEGIN_PGML
Enter the matrix [`[$A]`]:

[_]*{$A}
END_PGML

ENDDOCUMENT();
```

With this problem enter `S, -1, 1, 0` for the matrix entries.  Prior
to openwebwork#1004 this displayed correctly.  With openwebwork#1004 this is escaped twice,
and so you see the HTML code displayed.  With this pull request this is
again displayed correctly.
drgrice1 added a commit to drgrice1/pg that referenced this pull request Mar 20, 2024
This backs up one step from what was done in openwebwork#1004.  Instead of calling
`protectHTML` on `$ans->{student_ans}` in the `cmp_error` method, that
is instead called in the `cmp_parse` method in the case that the
`$ans->{student_value}` is undefined.

With openwebwork#1004, if `student_value` was defined, and then a problem author
calls `Value::Error` in a custom answer checker, it results in the
`student_ans` being escaped twice because it is escaped in `cmp_parse`
and then again after the custom answer checker is called.  With this
approach the `student_ans` is escaped when `cmp_parse` is called in
either case regardless if if `student_value` is defined, and then not
again later (if `student_value` is defined and thus the checker is
called)

This is also before the `format_matrix` method is called for array
answers.  This fixes an issue also caused by escaping those already HTML
formatted answers. In that case the `student_ans` is completely
redefined after this from the `student_formula`.  With openwebwork#1004, the
`student_ans` is first HTML formatted in this case, and then later
escaped which results in an incorrect display.

This of course still fixes the issue that openwebwork#1004 attempted to fix,
because the `student_value` is not defined, and so the `protectHTML` now
called in `cmp_parse` covers this case.

I am sure that this is not the end of this issue, but is better than
both before openwebwork#1004 and after.  I think that something along the lines of
@dpvc's suggestion in
openwebwork#990 (comment) will
be needed to fully resolve this issue.  I suggest that rather than
having `student_ans_text`, `student_ans_html`, `student_ans_latex`, and
`preview_ans_text` as suggested there, we use `student_ans`,
`preview_latex_string`, and `preview_text_string`.  `student_ans` would
always remain a text answer, and never be HTML formatted,
`preview_ans_latex` would stay the same and be LaTeX, and
`preview_text_string` would always be HTML.  The naming is not the best
since `preview_text_string` is actually HTML, but it is the closest to
the current usage, and so would take the least work.  Note that
currently `preview_text_string` is not actually used for anything.  Even
though it is documented in `lib/AnswerHash.pm` as being what is supposed
to be displayed for the preview.  So this proposal just aligns that
answer hash key with its intended use.

Test cases:

```
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix')->flags->set(requireConstantVectors => 1);
Context()->variables->are(s => 'Real', t => 'Real');

$ans     = Formula('s<1, 0> + t<0, 1>');
$ans_cmp = $ans->cmp(
    checker => sub {
        my ($c, $s, $self) = @_;
        Value::Error('Try again') unless $c == $s;
        return 1;
    }
);

BEGIN_PGML
Enter [`[$ans]`]: [_]{$ans_cmp}
END_PGML

ENDDOCUMENT();
```

With this problem enter `<s,0>+t<0,1>`.  Prior to openwebwork#1004 the first vector
would disappear from the displayed answer because `student_ans` was not
escaped. After openwebwork#1004 and still with this pull request this is displayed
correctly.

Also with this problem enter `s<1,0>+t<0,2>`.  Prior to openwebwork#1004 this
displayed correctly.  With openwebwork#1004 it is displayed as
`s*&lt;1,0&gt;+t*&lt;0,2&gt;`.  With this pull request is is displayed
correctly.

```
DOCUMENT();

loadMacros('PGstandard.pl', 'PGML.pl');

Context('Matrix');
$A = Matrix([ [ 1, 0 ], [ 0, -1 ] ]);

BEGIN_PGML
Enter the matrix [`[$A]`]:

[_]*{$A}
END_PGML

ENDDOCUMENT();
```

With this problem enter `S, -1, 1, 0` for the matrix entries.  Prior
to openwebwork#1004 this displayed correctly.  With openwebwork#1004 this is escaped twice,
and so you see the HTML code displayed.  With this pull request this is
again displayed correctly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants