@pretextbook/pretext-html 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,5 +3,5 @@
3
3
  "repository": "PreTeXtBook/pretext",
4
4
  "ref": "master"
5
5
  },
6
- "refreshed": "2026-08-21T22:01:23.781Z"
6
+ "refreshed": "2026-08-31T02:38:18.809Z"
7
7
  }
@@ -50,6 +50,14 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
50
50
  <!-- available for extraction. -->
51
51
  <xsl:variable name="exercise-style" select="'dynamic'"/>
52
52
 
53
+ <!-- A second Catch-22, of the same shape. A publisher may hold GeoGebra -->
54
+ <!-- applets behind a play button, but then this pass would photograph the -->
55
+ <!-- button rather than the applet, and the resulting image is what stands -->
56
+ <!-- in for the applet in static output. Worse, that image is exactly what -->
57
+ <!-- would be wanted to fill the empty preview a play button leaves for an -->
58
+ <!-- applet GeoGebra does not host. So the election is overridden here. -->
59
+ <xsl:variable name="b-geogebra-play-button" select="false()"/>
60
+
53
61
  <!-- @preview indicates custom image is present -->
54
62
  <!-- Stylesheet output is text, with "unique-id" -->
55
63
  <!-- of each interactive, one per line, to be -->
@@ -723,35 +723,6 @@
723
723
  <xsl:call-template name="begin-block">
724
724
  <xsl:with-param name="block-title">Header</xsl:with-param>
725
725
  </xsl:call-template>
726
- <xsl:if test="not($b-human-readable)">
727
- <!-- see select-latex-macros template -->
728
- <xsl:variable name="macros">
729
- <xsl:call-template name="select-latex-macros"/>
730
- </xsl:variable>
731
- <xsl:if test="$macros != ''">
732
- <xsl:variable name="wrapped-macros">
733
- <xsl:text>&lt;div style="display:none;">\(</xsl:text>
734
- <xsl:value-of select="$macros" />
735
- <xsl:text>\)&lt;/div></xsl:text>
736
- </xsl:variable>
737
- <xsl:variable name="delimiter">
738
- <xsl:call-template name="find-unused-character">
739
- <xsl:with-param name="string" select="$wrapped-macros"/>
740
- <!-- https://stackoverflow.com/questions/43617820/what-are-the-legal-delimiters-for-perl-5s-pick-your-own-quotes-operators -->
741
- <!-- NB: don't use (), <>, [], {}, because as perl delimiters, closer must be the right version; too complicated to check for -->
742
- <xsl:with-param name="charset" select="concat($apos,'|/?.,+-_~`!@$%^&amp;*')"/>
743
- </xsl:call-template>
744
- </xsl:variable>
745
- <xsl:text>TEXT(MODES(PTX=&gt;'',HTML=&gt;</xsl:text>
746
- <xsl:if test="$delimiter != $apos">
747
- <xsl:text>q</xsl:text>
748
- </xsl:if>
749
- <xsl:value-of select="$delimiter"/>
750
- <xsl:value-of select="$wrapped-macros"/>
751
- <xsl:value-of select="$delimiter"/>
752
- <xsl:text>));&#xa;</xsl:text>
753
- </xsl:if>
754
- </xsl:if>
755
726
  <xsl:text>&#xa;</xsl:text>
756
727
  </xsl:template>
757
728
 
@@ -1034,9 +1005,7 @@
1034
1005
  <xsl:value-of select="$standard-macros" />
1035
1006
  <xsl:value-of select="$implied-macros" />
1036
1007
  <xsl:value-of select="$user-macros" />
1037
- <xsl:if test=".//latex-image or ancestor::exercisegroup/introduction//latex-image">
1038
- <xsl:value-of select="$ptx-pg-macros" />
1039
- </xsl:if>
1008
+ <xsl:value-of select="$ptx-pg-macros" />
1040
1009
  <xsl:value-of select="$course-macros" />
1041
1010
  <xsl:text>);</xsl:text>
1042
1011
  <xsl:text>&#xa;</xsl:text>
@@ -1361,40 +1330,6 @@
1361
1330
  <xsl:text>&#xa;</xsl:text>
1362
1331
  </xsl:template>
1363
1332
 
1364
- <!-- Inside math we need to print definitions for PTX author-defined -->
1365
- <!-- LaTeX macros to support WeBWorK's images display mode. -->
1366
-
1367
- <!-- TODO: This named template examines the current context (see '.' in -->
1368
- <!-- contains() below), so should be a match template. But its recursive -->
1369
- <!-- implementation makes it a named template for now. -->
1370
- <xsl:template name="select-latex-macros">
1371
- <xsl:param name="macros" select="$latex-macros" />
1372
- <xsl:variable name="trimmed-start">
1373
- <xsl:if test="contains($macros, '\newcommand{')">
1374
- <xsl:value-of select="substring-after($macros, '\newcommand{')"/>
1375
- </xsl:if>
1376
- </xsl:variable>
1377
- <xsl:variable name="macro-name">
1378
- <xsl:if test="contains($trimmed-start, '}')">
1379
- <xsl:value-of select="substring-before($trimmed-start, '}')"/>
1380
- </xsl:if>
1381
- </xsl:variable>
1382
- <xsl:variable name="macro-command">
1383
- <xsl:value-of select="substring-before($macros, '&#xa;')"/>
1384
- </xsl:variable>
1385
- <xsl:variable name="next-lines">
1386
- <xsl:value-of select="substring-after($macros, '&#xa;')"/>
1387
- </xsl:variable>
1388
- <xsl:if test="contains(., $macro-name)">
1389
- <xsl:value-of select="normalize-space($macro-command)"/>
1390
- </xsl:if>
1391
- <xsl:if test="not($next-lines = '')">
1392
- <xsl:call-template name="select-latex-macros">
1393
- <xsl:with-param name="macros" select="$next-lines"/>
1394
- </xsl:call-template>
1395
- </xsl:if>
1396
- </xsl:template>
1397
-
1398
1333
  <!-- ##################################################################### -->
1399
1334
  <!-- ##################################################################### -->
1400
1335
  <!-- Above: templates for elements that only ever apply within a webwork -->
@@ -1490,9 +1425,6 @@
1490
1425
  <xsl:template match="m">
1491
1426
  <xsl:param name="b-human-readable" />
1492
1427
  <xsl:text>[`</xsl:text>
1493
- <xsl:if test="$b-human-readable">
1494
- <xsl:call-template name="select-latex-macros"/>
1495
- </xsl:if>
1496
1428
  <xsl:apply-templates select="text()|var" />
1497
1429
  <!-- look ahead to absorb immediate clause-ending punctuation -->
1498
1430
  <xsl:apply-templates select="." mode="get-clause-punctuation" />
@@ -1507,9 +1439,6 @@
1507
1439
  <xsl:call-template name="potential-list-indent" />
1508
1440
  </xsl:if>
1509
1441
  <xsl:text>[```</xsl:text>
1510
- <xsl:if test="$b-human-readable">
1511
- <xsl:call-template name="select-latex-macros"/>
1512
- </xsl:if>
1513
1442
  <!-- only a single mrow as a child (transition from old "me") -->
1514
1443
  <xsl:apply-templates select="mrow/text()|mrow/var" />
1515
1444
  <!-- look ahead to absorb immediate clause-ending punctuation -->
@@ -1591,9 +1520,6 @@
1591
1520
  <xsl:call-template name="potential-list-indent" />
1592
1521
  </xsl:if>
1593
1522
  <xsl:text>[```</xsl:text>
1594
- <xsl:if test="$b-human-readable">
1595
- <xsl:call-template name="select-latex-macros"/>
1596
- </xsl:if>
1597
1523
  <xsl:value-of select="$content" />
1598
1524
  <xsl:if test="ancestor::ul|ancestor::ol">
1599
1525
  <xsl:call-template name="potential-list-indent" />
@@ -3611,6 +3611,25 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
3611
3611
  </xsl:if>
3612
3612
  </xsl:template>
3613
3613
 
3614
+ <!-- A list ("ol", "ul", "dl") may stand bare at the top level -->
3615
+ <!-- of a "slide" or "subslide", an authoring convenience -->
3616
+ <!-- particular to the slideshow genre. Internally we keep the -->
3617
+ <!-- main grammar's single shape - a list lives within a -->
3618
+ <!-- paragraph - so every later consumer of the tree meets only -->
3619
+ <!-- one form. The manufactured paragraph does not survive to -->
3620
+ <!-- output as an HTML "p": the Reveal.js conversion explodes -->
3621
+ <!-- any paragraph containing displays, and for a paragraph that -->
3622
+ <!-- is exactly one list the explosion is precisely the bare -->
3623
+ <!-- list again. A @pause stays on the list itself, where the -->
3624
+ <!-- list item templates consult it. -->
3625
+ <xsl:template match="slide/ol|slide/ul|slide/dl|subslide/ol|subslide/ul|subslide/dl" mode="repair">
3626
+ <p>
3627
+ <xsl:copy>
3628
+ <xsl:apply-templates select="node()|@*" mode="repair"/>
3629
+ </xsl:copy>
3630
+ </p>
3631
+ </xsl:template>
3632
+
3614
3633
 
3615
3634
  <!-- ############################## -->
3616
3635
  <!-- Killed, in Chronological Order -->
@@ -4915,13 +4934,21 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
4915
4934
  <!-- we want the stylesheet to be independent, and the template is -->
4916
4935
  <!-- also applied here. -->
4917
4936
 
4918
- <!-- Every element carrying an "@pi:assembly-id" stamp reports it -->
4919
- <!-- through this single template. The match list is deliberately -->
4920
- <!-- explicit — media and images, data files, STACK problems, and -->
4921
- <!-- the fill-in dynamic-substitution owners (the exercise-like -->
4922
- <!-- elements, or a "task" they contain, whichever holds "setup") -->
4923
- <!-- — so the BUG fallback below can catch an unexpected -->
4924
- <!-- application. -->
4937
+ <!-- Every element carrying an "@pi:assembly-id" stamp reports it -->
4938
+ <!-- through this single template. The match list is deliberately -->
4939
+ <!-- explicit — media and images, data files, STACK problems, and -->
4940
+ <!-- the fill-in dynamic-substitution owners (the exercise-like -->
4941
+ <!-- elements, or a "task" they contain, whichever holds "setup") -->
4942
+ <!-- — so the BUG fallback below can catch an unexpected -->
4943
+ <!-- application. -->
4944
+ <!-- -->
4945
+ <!-- The stamp belongs to the assembly, laid down partway through -->
4946
+ <!-- the phases so that the later ones can coordinate on it. It is -->
4947
+ <!-- read here, and in the extraction stylesheets that feed those -->
4948
+ <!-- phases, and nowhere else. A conversion wants the "unique-id" -->
4949
+ <!-- template instead: the two agree for most elements but not for -->
4950
+ <!-- all, so a conversion reading this value can form a name that -->
4951
+ <!-- nothing else in the build uses. -->
4925
4952
  <xsl:template match="audio|video|interactive|image
4926
4953
  | datafile
4927
4954
  | exercise/stack
@@ -11954,6 +11954,27 @@ http://andrewmccarthy.ie/2014/11/06/swung-dash-in-latex/
11954
11954
  <xsl:with-param name="message" select="'an &quot;ol&quot; is no longer a child of an &quot;exercise&quot; &quot;statement&quot;; a list belongs inside a &quot;p&quot;. We will wrap it for you, and lettered exercise parts will letter as before. Please convert: structure true parts with &quot;task&quot;, letter a plain list with marker=&quot;(a)&quot;, or consider an &quot;exercisegroup&quot; and its cols attribute for a compact multi-column layout'"/>
11955
11955
  </xsl:call-template>
11956
11956
  <!-- -->
11957
+ <!-- 2026-08-23 a "sidebyside" requires at least two panels -->
11958
+ <xsl:call-template name="deprecation-message">
11959
+ <xsl:with-param name="occurrences" select="&quot;$document-root//sidebyside[count(*) = 1][not(ancestor::interactive)]&quot;" />
11960
+ <xsl:with-param name="date-string" select="'2026-08-23'" />
11961
+ <xsl:with-param name="message" select="'a &quot;sidebyside&quot; now requires at least two panels. Conversions will continue to honor a single panel until at least 2028-08-23. Please convert: to size or center a lone &quot;image&quot;, use its &quot;width&quot; attribute; otherwise place the lone item outside any &quot;sidebyside&quot;'"/>
11962
+ </xsl:call-template>
11963
+ <!-- -->
11964
+ <!-- 2026-08-23 one "sidebyside" may not nest within another -->
11965
+ <xsl:call-template name="deprecation-message">
11966
+ <xsl:with-param name="occurrences" select="&quot;$document-root//sidebyside//sidebyside&quot;" />
11967
+ <xsl:with-param name="date-string" select="'2026-08-23'" />
11968
+ <xsl:with-param name="message" select="'one &quot;sidebyside&quot; may not appear within another, no matter how much structure intervenes. A nested &quot;sidebyside&quot; may behave unpredictably. Please relocate the inner &quot;sidebyside&quot; outside the outer one'"/>
11969
+ </xsl:call-template>
11970
+ <!-- -->
11971
+ <!-- 2026-08-23 an "sbsgroup" requires at least two "sidebyside" -->
11972
+ <xsl:call-template name="deprecation-message">
11973
+ <xsl:with-param name="occurrences" select="&quot;$document-root//sbsgroup[count(sidebyside) = 1]&quot;" />
11974
+ <xsl:with-param name="date-string" select="'2026-08-23'" />
11975
+ <xsl:with-param name="message" select="'an &quot;sbsgroup&quot; now requires at least two &quot;sidebyside&quot;. A group of one behaves exactly like the &quot;sidebyside&quot; alone, so use the &quot;sidebyside&quot; by itself, with the layout attributes moved onto it'"/>
11976
+ </xsl:call-template>
11977
+ <!-- -->
11957
11978
  </xsl:template>
11958
11979
 
11959
11980
  <!-- Miscellaneous -->
@@ -819,6 +819,14 @@
819
819
  <link href="../{$css-dir}/epub.css" rel="stylesheet" type="text/css"/>
820
820
  </xsl:otherwise>
821
821
  </xsl:choose>
822
+ <!-- Custom list markers are "@counter-style" rules derived from -->
823
+ <!-- the source, so they ride along in every content file's head -->
824
+ <xsl:if test="$b-needs-custom-marker-css">
825
+ <style>
826
+ <xsl:text>&#xa;</xsl:text>
827
+ <xsl:apply-templates select="exsl:node-set($ol-markers)//ol-marker" mode="ol-marker-style"/>
828
+ </style>
829
+ </xsl:if>
822
830
  </xsl:template>
823
831
 
824
832
  <!-- ############# -->
@@ -585,6 +585,16 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
585
585
  role="H1">
586
586
  <xsl:apply-templates select="." mode="link-id-attribute"/>
587
587
  <xsl:apply-templates select="." mode="title-full"/>
588
+ <!-- A subtitle belongs to the heading, as it does in HTML, so it -->
589
+ <!-- sits inside this block rather than following it. Lighter and -->
590
+ <!-- smaller than the title, and on a line of its own. -->
591
+ <xsl:if test="subtitle">
592
+ <fo:block font-size="60%"
593
+ font-weight="normal"
594
+ space-before="0.5em">
595
+ <xsl:apply-templates select="." mode="subtitle"/>
596
+ </fo:block>
597
+ </xsl:if>
588
598
  </fo:block>
589
599
  </xsl:template>
590
600
 
@@ -228,6 +228,7 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
228
228
  <xsl:variable name="b-has-sage" select="boolean($document-root//sage)"/>
229
229
  <xsl:variable name="b-has-sfrac" select="boolean($document-root//m[contains(text(),'sfrac')] or $document-root//mrow[contains(text(),'sfrac')])" />
230
230
  <xsl:variable name="b-has-geogebra" select="boolean($document-root//interactive[@platform='geogebra'])"/>
231
+ <xsl:variable name="b-has-doenetml" select="boolean($document-root//interactive[@platform='doenetml'])"/>
231
232
  <xsl:variable name="b-has-mermaid" select="boolean($document-root//image[mermaid]|/image[mermaid])"/>
232
233
  <!-- 2018-04-06: jsxgraph deprecated -->
233
234
  <xsl:variable name="b-has-jsxgraph" select="boolean($document-root//jsxgraph)"/>
@@ -244,6 +245,15 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
244
245
  <xsl:variable name="ol-markers">
245
246
  <ol-markers>
246
247
  <xsl:apply-templates select="$document-root//ol[@marker and count(. | key('marker-key', @marker)[1]) = 1]" mode="ol-markers"/>
248
+ <!-- A legacy exercise-parts list letters as "(a)" with no -->
249
+ <!-- authored @marker; it joins the index as a reserved entry, -->
250
+ <!-- so one mechanism serves it, unless an authored "(a)" is -->
251
+ <!-- already present to share. The parenthesized letters are -->
252
+ <!-- LaTeX's custom for second-level lists, which PreTeXt -->
253
+ <!-- matches in every output (assembly stamps the adornments). -->
254
+ <xsl:if test="$document-root//ol[not(@marker) and @pi:format-code = 'a' and @pi:ordered-list-level = '1'] and not($document-root//ol[@marker = '(a)'])">
255
+ <ol-marker pi:format-code="a" marker="(a)" pi:marker-prefix="(" pi:marker-suffix=")" name="ptx-marker-0"/>
256
+ </xsl:if>
247
257
  </ol-markers>
248
258
  </xsl:variable>
249
259
  <!-- Following should be more efficient than 'select="boolean($document-root//ol[@marker])"' -->
@@ -350,12 +360,6 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
350
360
  <xsl:if test="not($b-subsetting) and not($b-portable-html)">
351
361
  <xsl:apply-templates select="." mode="make-xref-knowls"/>
352
362
  </xsl:if>
353
- <!-- custom ol marker css production -->
354
- <!-- A CDN cannot host these styles, since they are derived from the -->
355
- <!-- source. CDN builds get them inline instead, see "css-common". -->
356
- <xsl:if test="not($b-subsetting) and not($b-cdn-resources)">
357
- <xsl:call-template name="ol-marker-styles"/>
358
- </xsl:if>
359
363
  </xsl:template>
360
364
 
361
365
  <!-- However, some PTX document types do not have -->
@@ -2074,6 +2078,7 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
2074
2078
  <!-- this message, locate the apply-templates chain -->
2075
2079
  <!-- that omitted the parameter and add it. -->
2076
2080
  <xsl:message>PTX:BUG: "hN" template reached without a $heading-level parameter on element &lt;<xsl:value-of select="local-name(.)"/>&gt; at <xsl:for-each select="ancestor::*"><xsl:value-of select="local-name(.)"/><xsl:text>/</xsl:text></xsl:for-each><xsl:value-of select="local-name(.)"/>; defaulting to h1</xsl:message>
2081
+ <xsl:apply-templates select="." mode="location-report"/>
2077
2082
  <xsl:text>1</xsl:text>
2078
2083
  </xsl:otherwise>
2079
2084
  </xsl:choose>
@@ -6209,13 +6214,6 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
6209
6214
  <xsl:element name="{local-name(.)}">
6210
6215
  <xsl:attribute name="class">
6211
6216
  <xsl:apply-templates select="." mode="html-list-class" />
6212
- <xsl:variable name="ol-marker-class">
6213
- <xsl:apply-templates select="." mode="ol-marker-class" />
6214
- </xsl:variable>
6215
- <xsl:if test="not($ol-marker-class = '')">
6216
- <xsl:text> </xsl:text>
6217
- <xsl:value-of select="$ol-marker-class"/>
6218
- </xsl:if>
6219
6217
  <xsl:variable name="cols-class-name">
6220
6218
  <!-- HTML-specific, but in pretext-common.xsl -->
6221
6219
  <xsl:apply-templates select="." mode="number-cols-CSS-class"/>
@@ -6225,6 +6223,18 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
6225
6223
  <xsl:value-of select="$cols-class-name"/>
6226
6224
  </xsl:if>
6227
6225
  </xsl:attribute>
6226
+ <!-- a custom marker is a named "@counter-style" rule, inlined -->
6227
+ <!-- with the page's CSS, referenced from right here -->
6228
+ <xsl:variable name="ol-marker-name">
6229
+ <xsl:apply-templates select="." mode="ol-marker-name"/>
6230
+ </xsl:variable>
6231
+ <xsl:if test="not($ol-marker-name = '')">
6232
+ <xsl:attribute name="style">
6233
+ <xsl:text>list-style: </xsl:text>
6234
+ <xsl:value-of select="$ol-marker-name"/>
6235
+ <xsl:text>;</xsl:text>
6236
+ </xsl:attribute>
6237
+ </xsl:if>
6228
6238
  <xsl:attribute name="id">
6229
6239
  <xsl:apply-templates select="." mode="html-id" />
6230
6240
  </xsl:attribute>
@@ -6240,20 +6250,23 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
6240
6250
  </xsl:element>
6241
6251
  </xsl:template>
6242
6252
 
6243
- <xsl:template match="ol[@marker]" mode="ol-marker-class">
6253
+ <xsl:template match="ol[@marker]" mode="ol-marker-name">
6244
6254
  <xsl:variable name="marker-value" select="./@marker" />
6245
6255
  <xsl:for-each select="exsl:node-set($ol-markers)">
6246
6256
  <!-- Should be only one match since ol marker -->
6247
6257
  <!-- index node set contains no duplicates -->
6248
- <xsl:value-of select="key('marker-key', $marker-value)[1]/@classname"/>
6258
+ <xsl:value-of select="key('marker-key', $marker-value)[1]/@name"/>
6249
6259
  </xsl:for-each >
6250
6260
  </xsl:template>
6251
6261
 
6252
- <xsl:template match="ol[not(@marker) and @pi:format-code = 'a' and @pi:ordered-list-level = '1']" mode="ol-marker-class">
6253
- <xsl:text>lower-alpha-level-1</xsl:text>
6262
+ <!-- the reserved "(a)" entry, or an authored twin, by the same lookup -->
6263
+ <xsl:template match="ol[not(@marker) and @pi:format-code = 'a' and @pi:ordered-list-level = '1']" mode="ol-marker-name">
6264
+ <xsl:for-each select="exsl:node-set($ol-markers)">
6265
+ <xsl:value-of select="key('marker-key', '(a)')[1]/@name"/>
6266
+ </xsl:for-each>
6254
6267
  </xsl:template>
6255
6268
 
6256
- <xsl:template match="ol|ul" mode="ol-marker-class"/>
6269
+ <xsl:template match="ol|ul" mode="ol-marker-name"/>
6257
6270
 
6258
6271
  <xsl:template match="ol[@marker]" mode="ol-markers">
6259
6272
  <xsl:element name="ol-marker">
@@ -6261,38 +6274,39 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
6261
6274
  <xsl:copy-of select="@marker"/>
6262
6275
  <xsl:copy-of select="@pi:marker-prefix"/>
6263
6276
  <xsl:copy-of select="@pi:marker-suffix"/>
6264
- <xsl:attribute name="classname">
6265
- <xsl:text>ol-marker-</xsl:text>
6277
+ <xsl:attribute name="name">
6278
+ <xsl:text>ptx-marker-</xsl:text>
6266
6279
  <xsl:value-of select="position()" />
6267
6280
  </xsl:attribute>
6268
6281
  </xsl:element>
6269
6282
  </xsl:template>
6270
6283
 
6271
- <!-- Creates custom formatting for each unique ol/@marker -->
6284
+ <!-- One "@counter-style" rule per distinct marker. The author's -->
6285
+ <!-- prefix and suffix become CSS strings, escaped; the suffix gains -->
6286
+ <!-- the trailing space that separates a marker from its item. Each -->
6287
+ <!-- list references its rule by name from a "style" attribute, so -->
6288
+ <!-- these rules are the only shared CSS a custom marker needs. -->
6289
+ <!-- They cannot be per-list: an at-rule only lives in a stylesheet. -->
6290
+ <!-- Should WebKit ever support "content" on "::marker" (WebKit bug -->
6291
+ <!-- 204163), one static theme rule reading custom properties could -->
6292
+ <!-- replace all of this, and markers would be entirely per-list -->
6293
+ <!-- inline, with no shared rules and no marker index at all. -->
6272
6294
  <xsl:template match="ol-marker" mode="ol-marker-style">
6273
- <!-- format child li elements according to marker prefix/code/suffix -->
6274
- <xsl:text>ol.</xsl:text>
6275
- <xsl:value-of select="./@classname"/>
6276
- <xsl:text> &gt; li::marker { content: &quot;</xsl:text>
6277
- <xsl:value-of select="./@pi:marker-prefix" />
6278
- <xsl:text>&quot;counter(list-item,</xsl:text>
6295
+ <xsl:text>@counter-style </xsl:text>
6296
+ <xsl:value-of select="./@name"/>
6297
+ <xsl:text> { system: extends </xsl:text>
6279
6298
  <xsl:apply-templates select="." mode="html-list-class" />
6280
- <xsl:text>)&quot;</xsl:text>
6281
- <xsl:value-of select="./@pi:marker-suffix" />
6282
- <xsl:text> &quot;; }&#xa;</xsl:text>
6299
+ <xsl:text>; prefix: '</xsl:text>
6300
+ <xsl:call-template name="css-string-escape">
6301
+ <xsl:with-param name="text" select="./@pi:marker-prefix"/>
6302
+ </xsl:call-template>
6303
+ <xsl:text>'; suffix: '</xsl:text>
6304
+ <xsl:call-template name="css-string-escape">
6305
+ <xsl:with-param name="text" select="./@pi:marker-suffix"/>
6306
+ </xsl:call-template>
6307
+ <xsl:text> '; }&#xa;</xsl:text>
6283
6308
  </xsl:template>
6284
6309
 
6285
- <!-- CSS file for custom ol markers -->
6286
- <xsl:template name="ol-marker-styles">
6287
- <!-- We don't produce a file if it will be empty. This would -->
6288
- <!-- "naturally" be the case, but we have a boolean anyway. -->
6289
- <xsl:if test="$b-needs-custom-marker-css">
6290
- <xsl:variable name="ol-marker-nodes" select="exsl:node-set($ol-markers)" />
6291
- <exsl:document href="{$html.css.dir}/ol-markers.css" method="text">
6292
- <xsl:apply-templates select="$ol-marker-nodes//ol-marker" mode="ol-marker-style" />
6293
- </exsl:document>
6294
- </xsl:if>
6295
- </xsl:template>
6296
6310
 
6297
6311
  <!-- We let CSS react to narrow titles for dl -->
6298
6312
  <!-- But no support for multiple columns -->
@@ -10199,6 +10213,10 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
10199
10213
  <xsl:attribute name="src">
10200
10214
  <xsl:apply-templates select="." mode="iframe-filename" />
10201
10215
  </xsl:attribute>
10216
+ <!-- how the coordinator script recognizes an activity it manages -->
10217
+ <xsl:if test="(@platform = 'doenetml') and $b-doenetml-coordinator">
10218
+ <xsl:attribute name="data-doenet-coordinate">true</xsl:attribute>
10219
+ </xsl:if>
10202
10220
  <xsl:apply-templates select="." mode="iframe-accessibility-attributes"/>
10203
10221
  </iframe>
10204
10222
  <!-- possibly give a long description -->
@@ -10359,6 +10377,20 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
10359
10377
  <script src="{$d3-library-url}"></script>
10360
10378
  </xsl:template>
10361
10379
 
10380
+ <!-- The version of DoenetML a document asks for, absent any request from -->
10381
+ <!-- an individual "interactive". Also the version of the coordinator -->
10382
+ <!-- script a page carrying DoenetML activities loads. -->
10383
+ <xsl:variable name="doenetml-document-version">
10384
+ <xsl:choose>
10385
+ <xsl:when test="$docinfo/doenetml/@version">
10386
+ <xsl:value-of select="$docinfo/doenetml/@version"/>
10387
+ </xsl:when>
10388
+ <xsl:otherwise>
10389
+ <xsl:text>latest</xsl:text>
10390
+ </xsl:otherwise>
10391
+ </xsl:choose>
10392
+ </xsl:variable>
10393
+
10362
10394
  <!-- DoenetML header libraries -->
10363
10395
  <xsl:template match="interactive[@platform = 'doenetml']" mode="header-libraries">
10364
10396
  <xsl:variable name="doenet-version">
@@ -10366,11 +10398,8 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
10366
10398
  <xsl:when test="@version">
10367
10399
  <xsl:value-of select="@version"/>
10368
10400
  </xsl:when>
10369
- <xsl:when test="$docinfo/doenetml/@version">
10370
- <xsl:value-of select="$docinfo/doenetml/@version"/>
10371
- </xsl:when>
10372
10401
  <xsl:otherwise>
10373
- <xsl:text>latest</xsl:text>
10402
+ <xsl:value-of select="$doenetml-document-version"/>
10374
10403
  </xsl:otherwise>
10375
10404
  </xsl:choose>
10376
10405
  </xsl:variable>
@@ -10687,6 +10716,15 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
10687
10716
  </xsl:choose>
10688
10717
  <xsl:text>,&#xa;</xsl:text>
10689
10718
  </xsl:if>
10719
+ <!-- Unlike the parameters above, this one is the publisher's rather than -->
10720
+ <!-- the author's. GeoGebra renders a preview image and a play button in -->
10721
+ <!-- place of the applet, and only starts the applet when a reader presses -->
10722
+ <!-- it, so a page carrying several applets need not start them all at -->
10723
+ <!-- once. GeoGebra's own default is no button, which is also ours, so -->
10724
+ <!-- nothing is emitted unless a publisher asks for it. -->
10725
+ <xsl:if test="$b-geogebra-play-button">
10726
+ <xsl:text>playButton: true,&#xa;</xsl:text>
10727
+ </xsl:if>
10690
10728
  <xsl:text>width:</xsl:text><xsl:value-of select="$material-width" />
10691
10729
  <xsl:text>,&#xa;</xsl:text>
10692
10730
  <xsl:text>height:</xsl:text><xsl:value-of select="$material-height" />
@@ -10704,6 +10742,24 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
10704
10742
  <xsl:value-of select="$applet-parameters" />
10705
10743
  <xsl:text>, true);&#xa;</xsl:text>
10706
10744
 
10745
+ <!-- GeoGebra draws its play button in front of a preview image, and it -->
10746
+ <!-- has one to offer only for an applet it hosts itself. An applet -->
10747
+ <!-- built from a file, or written from scratch, gets an empty box. A -->
10748
+ <!-- screenshot of every interactive is made for static output, so we -->
10749
+ <!-- hand GeoGebra that one, and then every applet alike shows what a -->
10750
+ <!-- reader is being invited to start. The second and third arguments -->
10751
+ <!-- would be a loading indicator and the button's own image; GeoGebra -->
10752
+ <!-- supplies the button, and no indicator is wanted in front of a -->
10753
+ <!-- picture of the applet itself. -->
10754
+ <xsl:if test="$b-geogebra-play-button">
10755
+ <xsl:value-of select="$applet-name"/>
10756
+ <xsl:text>.setPreviewImage('</xsl:text>
10757
+ <xsl:value-of select="$generated-directory"/>
10758
+ <xsl:text>preview/</xsl:text>
10759
+ <xsl:apply-templates select="ancestor::interactive" mode="unique-id"/>
10760
+ <xsl:text>-preview.png', null, null);&#xa;</xsl:text>
10761
+ </xsl:if>
10762
+
10707
10763
  <xsl:text>resolve(</xsl:text><xsl:value-of select="$applet-name" /><xsl:text>);})&#xa;</xsl:text>
10708
10764
  <xsl:text>.then((</xsl:text><xsl:value-of select="$applet-name" /><xsl:text>) => {&#xa;</xsl:text>
10709
10765
  <!-- inject the applet into the div below -->
@@ -11526,6 +11582,10 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
11526
11582
  <xsl:call-template name="scorm-js"/>
11527
11583
  <xsl:call-template name="diagcess-header"/>
11528
11584
  <xsl:call-template name="lti-iframe-resizer"/>
11585
+ <!-- NB: deliberately not in the iframe head cache above - the -->
11586
+ <!-- coordinator belongs on the page that *holds* the activities, -->
11587
+ <!-- and a standalone page holds the one it was extracted for. -->
11588
+ <xsl:call-template name="doenetml-coordinator" />
11529
11589
  </xsl:variable>
11530
11590
 
11531
11591
  <!-- Content used by simple-file-wrap -->
@@ -14603,6 +14663,51 @@ TODO:
14603
14663
  </xsl:if>
14604
14664
  </xsl:template>
14605
14665
 
14666
+ <!-- DoenetML coordinator -->
14667
+ <!-- A "coordinator" script, served alongside the DoenetML bundle that -->
14668
+ <!-- the activities already load, takes charge of a page's activity -->
14669
+ <!-- "iframe"s so that a page carrying many of them need not run them -->
14670
+ <!-- all at once. See publisher-variables.xsl for what it does and for -->
14671
+ <!-- the publisher's control over it. The activity pages need no -->
14672
+ <!-- cooperation - the coordinator marks each activity's URL and the -->
14673
+ <!-- bundle recognizes the mark - so this one script tag is all of it. -->
14674
+ <xsl:template name="doenetml-coordinator">
14675
+ <xsl:if test="$b-has-doenetml and $b-doenetml-coordinator">
14676
+ <xsl:variable name="doenet-coordinator-url">
14677
+ <xsl:text>https://cdn.jsdelivr.net/npm/@doenet/standalone@</xsl:text>
14678
+ <xsl:value-of select="$doenetml-document-version"/>
14679
+ <xsl:text>/coordinator.js</xsl:text>
14680
+ </xsl:variable>
14681
+ <!-- A document pinned to a DoenetML version from 0.7.21 through -->
14682
+ <!-- 0.7.24 gets a coordinator that restores a parked activity's -->
14683
+ <!-- work itself, racing a host that restores saved work of its -->
14684
+ <!-- own - and the older copy can win, replacing work a reader -->
14685
+ <!-- just did. The publisher may not have read the paragraph in -->
14686
+ <!-- the Guide that says so, and both facts are visible here, so -->
14687
+ <!-- warn. A partial pin like "0.7" floats to the newest release -->
14688
+ <!-- and is safe; its patch part is empty, and fails the numeric -->
14689
+ <!-- comparisons below. -->
14690
+ <xsl:if test="$b-host-runestone or $b-host-scorm">
14691
+ <xsl:variable name="doenetml-pin-patch" select="substring-after(substring-after($doenetml-document-version, '.'), '.')"/>
14692
+ <xsl:if test="(substring-before($doenetml-document-version, '.') = '0') and (substring-before(substring-after($doenetml-document-version, '.'), '.') = '7') and (number($doenetml-pin-patch) &gt;= 21) and (number($doenetml-pin-patch) &lt;= 24)">
14693
+ <xsl:message>PTX:WARNING: this document pins DoenetML version <xsl:value-of select="$doenetml-document-version"/>, whose activity coordinator can replace a reader's saved work with an older copy when the book is hosted on Runestone or as SCORM. Pin version 0.7.25 or later, or set the "coordinator" attribute of the "doenetml" element of the publication file to "no"</xsl:message>
14694
+ </xsl:if>
14695
+ </xsl:if>
14696
+ <!-- The selector confines the script to DoenetML activities (see -->
14697
+ <!-- the "data-doenet-coordinate" attribute placed on their -->
14698
+ <!-- "iframe"s); the script's own default would also sweep up every -->
14699
+ <!-- "-if.html" iframe, which for PreTeXt means every other -->
14700
+ <!-- platform's interactive too. -->
14701
+ <!-- Two notes on the tag itself: it is a classic script, so -->
14702
+ <!-- "document.currentScript" still supplies its options under -->
14703
+ <!-- "defer", which keeps a CDN fetch from blocking every page of -->
14704
+ <!-- the book; and the script reads the shared-core-workers value -->
14705
+ <!-- as anything but the string "false", so the publisher's "no" -->
14706
+ <!-- must be stringified as "false" rather than passed through. -->
14707
+ <script defer="defer" src="{$doenet-coordinator-url}" data-iframe-selector="iframe[data-doenet-coordinate]" data-max-live-viewers="{$doenetml-max-live-viewers}" data-max-concurrent-boots="{$doenetml-max-concurrent-boots}" data-shared-core-workers="{$b-doenetml-shared-core-workers}"></script>
14708
+ </xsl:if>
14709
+ </xsl:template>
14710
+
14606
14711
  <!-- JSXGraph -->
14607
14712
  <xsl:template name="jsxgraph">
14608
14713
  <xsl:if test="$b-has-jsxgraph">
@@ -14647,22 +14752,16 @@ TODO:
14647
14752
 
14648
14753
  <!-- CSS header -->
14649
14754
  <xsl:template name="css-common">
14650
- <!-- Temporary until css handling overhaul by ascholer complete -->
14755
+ <!-- Custom list markers are "@counter-style" rules derived from the -->
14756
+ <!-- source, one per distinct marker, referenced by name from each -->
14757
+ <!-- list's "style" attribute. Inlined unconditionally: they are -->
14758
+ <!-- tiny, they cannot live on a CDN, and portable HTML has no place -->
14759
+ <!-- to link out to anyway. -->
14651
14760
  <xsl:if test="$b-needs-custom-marker-css">
14652
- <xsl:choose>
14653
- <!-- These styles are derived from the source, so they are not on -->
14654
- <!-- the CDN and "$html.css.dir" does not point at them. Inline -->
14655
- <!-- them: there is one short rule per unique author-supplied -->
14656
- <!-- marker, and portable HTML has no place to link out to anyway. -->
14657
- <xsl:when test="$b-cdn-resources">
14658
- <style>
14659
- <xsl:apply-templates select="exsl:node-set($ol-markers)//ol-marker" mode="ol-marker-style"/>
14660
- </style>
14661
- </xsl:when>
14662
- <xsl:otherwise>
14663
- <link href="{$html.css.dir}/ol-markers.css" rel="stylesheet" type="text/css"/>
14664
- </xsl:otherwise>
14665
- </xsl:choose>
14761
+ <style>
14762
+ <xsl:text>&#xa;</xsl:text>
14763
+ <xsl:apply-templates select="exsl:node-set($ol-markers)//ol-marker" mode="ol-marker-style"/>
14764
+ </style>
14666
14765
  </xsl:if>
14667
14766
  <!-- If extra CSS is specified, then unpack multiple CSS files -->
14668
14767
  <xsl:if test="not($html.css.extra = '')">
@@ -354,6 +354,10 @@ along with PreTeXt. If not, see <http://www.gnu.org/licenses/>.
354
354
  <xsl:text>.mathbook-content table tr.header-vertical th {writing-mode: vertical-rl; padding-left: 2em;}&#xa;</xsl:text>
355
355
  <xsl:text>.mathbook-content .sbspanel img {max-width: 100%;}&#xa;</xsl:text>
356
356
  <xsl:text>.mathbook-content .tablenotes {list-style: none; padding-left: 0;}&#xa;</xsl:text>
357
+ <!-- custom list markers, one "@counter-style" rule per -->
358
+ <!-- distinct marker, referenced from each list's -->
359
+ <!-- "style" attribute -->
360
+ <xsl:apply-templates select="exsl:node-set($ol-markers)//ol-marker" mode="ol-marker-style"/>
357
361
  <xsl:text>&lt;/style&gt;</xsl:text>
358
362
  <xsl:call-template name="end-string" />
359
363
  </xsl:with-param>