Skip to content

WeBWorK: sidebyside - #3053

Draft
Alex-Jordan wants to merge 3 commits into
PreTeXtBook:masterfrom
Alex-Jordan:ww-sbs
Draft

WeBWorK: sidebyside#3053
Alex-Jordan wants to merge 3 commits into
PreTeXtBook:masterfrom
Alex-Jordan:ww-sbs

Conversation

@Alex-Jordan

Copy link
Copy Markdown
Contributor

This lets sidebyside be used in a webwork.

The first commit carries the templates needed to make it happen. As well as removes the deprecation that was in place for a sidebyside in a webwork.

The second commit adds an example to the sample chapter. This has the effect of changing all seeds for representations of subsequent exercises, so a lot of files get trivial changes.

@rbeezer

rbeezer commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Are you bypassing the determination of implied widths when the layout parameters are formed? Shouldn't every such parameter be looked up in $layout-parameters?

For example, line 1598 of extract-pg.xsl.

str:tokenize(@widths)

will get widths directly from whatever the author writes, instead of whatever comes out of $layout-parameters.

I can imagine a day when a common width for all the panels gets converted into a long list of identical values in -assembly and then is dropped, along with any code that reacts to it.

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

I'm not sure I understood all that is possible with a $layout for a sidebyside. The model I looked at did not use $layout/width at the level of "compose-panels" (rather, now I see that it uses each $layout/width deeper at the level of "panel-panel"). But with PG, it needs to declare all the widths at the "compose-panels" level.

I changed it to loop through the $layout/width~s. It's better now, producing output like p(0.47}p{0.47}. Before it was producing p(47%}p{47%}, which works fine for PG HTML output. But breaks PG TeX output.

@rbeezer

rbeezer commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Thanks, @Alex-Jordan . It'll be great to have sidebyside as a WW option.

Review coming from Claude Code in a minute. My (cursory) visual review last night suggested something was up with sbsgroup. I think Claude has more.

Seeds: do we allow authors to set a @seed, so their static versions do not drift, like we are seeing here. I think it would be worthwhile to hard-code a @seed for each existing problem, so we don't get commits like this with spurious changes. It'd be an easy task for Claude, which I could knock off quickly.

@rbeezer

rbeezer commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Reviewed at 03708936, against the merge-base a6406e04. Line numbers below are in the PR head.

Schema still forbids what the XSL now emits

The deprecation is removed and the templates are in place, but schema/pretext.rnc is untouched. BlockStatementWW (line 1460) remains

BlockStatementWW =
            Paragraph |
            Preformatted |
            Tabular |
            ImageWW

with no sidebyside and no sbsgroup. The comment this PR deletes said as much: "such use will be caught by a deprecation warning as well as fail a schema validation."

Building -f assembly-version for the sample chapter at the merge-base and at the PR head, running jing on each, and taking the set difference of the error text gives exactly one error type new in the head:

error: element "sidebyside" not allowed here; expected element "image", "instruction", "p", "pre" or "tabular"

So the exercise added in the second commit does not validate.

An sbsgroup in a webwork aborts the whole extraction

extract-pg.xsl, <xsl:template match="sbsgroup"> (line 1615), reads $layout/number-panels (line 1623) and $layout/valign (line 1628). That template has no layout parameter, and there is no global one — the only layout in the file is the parameter on compose-panels at line 1583. libxslt reports this at run time and discards the entire result document:

runtime error: file xsl/extract-pg.xsl line 1623 element value-of
Variable 'layout' has not been declared.
XPath error : Undefined variable
error: file sample-chapter.ptx
xsltRunStylesheet : run failed

Reproduced by wrapping the new exercise's sidebyside in <sbsgroup width="47%">, which reaches line 1623, and separately in <sbsgroup valign="middle">, which reaches line 1628. Neither run produces an output file, so a single sbsgroup suppresses WeBWorK extraction for the entire document rather than for the one exercise. This is latent only for as long as the schema blocks sbsgroup inside a webwork; the schema change above makes it reachable.

Independently, this template overrides the sbsgroup template in pretext-common.xsl (line 5017), which means the pre-sbsgroup and post-sbsgroup hooks no longer fire for PG output. pretext-common.xsl offers <xsl:template name="sbsgroup-wrapper"> (line 5012) for exactly this purpose — "default wrapper does nothing, output modes may optionally provide some containing structure".

"b-human-readable" is lost inside a sidebyside

mode="panel-panel" declares <xsl:param name="b-human-readable"/> at line 1556, but the sidebyside template in pretext-common.xsl (line 4909) neither accepts nor forwards it — it supplies b-original, width, left-margin, right-margin, valign and heading-level. The parameter therefore defaults to empty, which is false, for every panel.

Adding a tabular panel to the new exercise and generating problem sets, where pretext-ww-problem-sets.xsl sets the parameter to true() at line 186, gives the compact form inside the sidebyside

[@DataTable([[PGML('A'),PGML('B'),],[PGML('C'),PGML('D'),],],align=>'*{2}{l}',valign=>'middle',);@]*

against the expanded form everywhere else in the same generated set

>> [@DataTable(
  [
    [PGML('[`(0,0)`]'),
     PGML('[`(0,1)`]'),
    ],
  ],
      align => '*{2}{l}',
      valign => 'middle',);@]* <<

A global variable will not serve, since extract-pg.xsl passes true() at line 215 and false() at line 225 within one run. The value has to be threaded through the sidebyside template.

Two conventions for p{} widths

compose-panels (line 1589) emits a bare fraction, align => 'p{0.47}p{0.47}'. The new sbsgroup template (line 1621) and the existing <xsl:template match="col" mode="texalignment"> (line 2546) both use mode="absolute-width-inches", which gives p{2.94in}. A bare 0.47 is not a LaTeX dimension, so the first form depends on niceTables interpreting it as a fraction. Which is intended? absolute-width-inches is already the convention elsewhere in the file.

Smaller points

  • Line 1562: <xsl:variable name="arguments"> in mode="panel-panel" is empty, so the <xsl:if test="$arguments != ''"> at line 1574 can never fire. Both can be dropped.
  • Line 1592: $layout/valign != 'top' is a node-set comparison, true when any panel is not top, but line 1594 emits only the first valign. Panels of top and middle produce valign => 'top', which is the default the test was meant to skip.
  • Line 1514: not(A or B) is rewritten as not(A|B) in the p template. The two are equivalent, and the change is unrelated to the feature.
  • Lines 1363 and 2432 use a union as a boolean, test="preceding-sibling::p|ancestor::sidebyside", as do lines 1538 and 1544 with not(ancestor::li|ancestor::sidebyside), where or states the intent directly.
  • Line 2989: potential-list-indent gains 2*count(ancestor::sidebyside), which encodes the panel indentation depth in a template otherwise shared with the list code.

The representation churn in the second commit is seed shift only, as the description says.

Claude Opus 4.8, acting as a review assistant for Rob Beezer

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

Working on sbsgroup, and will add a test example. In the meantime, I prepended a commit here to nail down sample chapter seeds. So the diff affects far fewer files now.

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

For PG to return valid PTX here, the PG version will need to be 2.21 or higher. What is the right way/place to document or enforce that? Documented only in the guide somewhere? If enforced, what stage of processing?

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

Trying to support sbsgroup is a challenge. How do you feel about:

  • I make this support only sidebyside for now, not sbsgroup. Someone is free to just author sequential sidebyside without wrapping them in an sbsgroup.
  • I think I could make it support sbsgroup in PTX source, but the sbsgroup element would not survive the round trip. Instead, you would just get back the sidebyside within, each now having @widths from the original sbsgroup where appropriate.

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

I think I should explain more about the fundamental issue here. In PG, there is such a thing now as a layout table. A layout table could have one row or more than one. When it comes to translating PG to PTX, I can convert a layout table to either a sidebyside or an sbsgroup depending on row count.

When we start with PTX, sidebyside or sbsgroup can have these attributes:

  1. @component, @landscape
  2. @valign, @valigns
  3. @width, @widths, @margins,

For class 1, there's really no counterpart in a PG layout table. So I'm not even trying to preserve those.

For class 2, I foresee no issue with preserving those.

For class 3, there will be no issue preserving those when translating a sidebyside to a PG layout table. But a PG layout table with multiple rows has no way to make one row use certain widths and margins, and then the next row use something different. So if we have an sbsgroup that wants widths and margins to vary one sidebyside to the next, there just is no PG structure for that. So the best I could do is pretend it was actually just a bare sequence of sidebyside in the first place. (Although I can still honor the attributes from the sbsgroup, pretending they had been on each sidebyside.)

I guess I am talking myself into doing that.

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

OK, this is both ready for review and not yet ready for review.

  • It's not ready, because you will not be able to test until the PTX WW server s using version 2.21. That version is not released until early next month, and then it will be up to @sean-fitzpatrick to upgrade the server. (I'm unsure if I still have access to it, as well as wondering if it's best that I don't meddle. But @sean-fitzpatrick, let me know if I should help there.)
  • It's also not ready because I've done nothing about validating that a server is 2.21 before attempting to process sidebyside in a webwork. If you have guidance about the best way to do that (or not to bother) I will happily follow.
  • Otherwise, it is ready, I think. I left sbsgroup out of the schema. But sidebyside is OK, with legal children being p, tabular, image, pre, and stack. That last one was a challenge on the PG side, but it works now. Also, getting that to work is partly why I gave up on sbsgroup.

I'll mark this as draft, since we at least need to wait for PG 2.21.

@Alex-Jordan
Alex-Jordan marked this pull request as draft July 22, 2026 07:19
@rbeezer

rbeezer commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Working on sbsgroup

I'm not versed in the subtleties, but in most other conversions, a sbsgroup is just a bunch of consecutive #sidebyside. For example, in LaTeX that arrangement allows for page-breaking mid-group.

It's not ready, because you will not be able to test until the PTX WW server is using version 2.21.

Which means it is not ready. And I just saw this is now a draft! ;-).

I've done nothing about validating that a server is 2.21

I really do not like the idea that PreTeXt source is valid or depending on which version or which server is in use. So one answer is we do not support this construction until 2.21 is the minimum supported version. The server version is reported in the Python. I guess you can scan each problem with lxml tools for a sidebyside and issue an error and replace with a placeholder. Our validation tools are too early in the assembly pipeline to know the server version and I don't think the check belongs in the conversions themselves.

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

Commentary (nothing to act on): If the changes here were in place for PTX, then PTX is indeed producing valid PG for PG 2.19 and later. The problem will be that PG 2.19 and PG 2.20 were broken. They did not have the needed code to produce valid static PTX for a layout table. They produce perfectly good HTML and TeX, and no one noticed the bug because there was no cause in those versions for PG to produce static PTX for a layout table.

So it's just a perspective, but PTX would be producing valid PG for all those versions. Some PG versions would have bugs with what they send back. (Bugs that break PTX schema, not that break XML validity.)

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.

2 participants