Skip to content

Commit 6785ca3

Browse files
author
Sanders Kleinfeld
committed
Adding parameterized handling via xref.elements.pagenum.in.class to add "pagenum" class values to XREFs to facilitate use of CSS Paged Media to add page numbers for paged outputs.
1 parent 3106b0a commit 6785ca3

File tree

7 files changed

+333
-3
lines changed

7 files changed

+333
-3
lines changed

htmlbook-xsl/chunk.xsl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ sect5:s
5959
links will be clickable -->
6060
<xsl:param name="url.in.parens" select="0"/>
6161

62+
<!-- Chunked output typically not used for print output, so disabling addition of "pagenum" classes on all XREFs -->
63+
<xsl:param name="xref.elements.pagenum.in.class"/>
64+
6265
<xsl:template match="/h:html">
6366
<xsl:apply-templates select="h:body"/>
6467
</xsl:template>
@@ -325,6 +328,8 @@ sect5:s
325328
<!-- All XREFs must be tagged with a @data-type containing XREF -->
326329
<xsl:template match="h:a[contains(@data-type, 'xref')]" name="process-as-xref">
327330
<xsl:param name="autogenerate-xrefs" select="$autogenerate-xrefs"/>
331+
<xsl:param name="xref.elements.pagenum.in.class" select="$xref.elements.pagenum.in.class"/>
332+
328333
<xsl:variable name="calculated-output-href">
329334
<xsl:call-template name="calculate-output-href">
330335
<xsl:with-param name="source-href-value" select="@href"/>
@@ -341,6 +346,11 @@ sect5:s
341346
<xsl:choose>
342347
<xsl:when test="(count(key('id', $href-anchor)) &gt; 0) and ($is-xref = 1)">
343348
<xsl:variable name="target" select="key('id', $href-anchor)[1]"/>
349+
<!-- If we can locate the target, reprocess class attribute to add "pagenum" class value if needed -->
350+
<xsl:apply-templates select="." mode="class.attribute">
351+
<xsl:with-param name="xref.elements.pagenum.in.class" select="$xref.elements.pagenum.in.class"/>
352+
<xsl:with-param name="xref.target" select="$target"/>
353+
</xsl:apply-templates>
344354
<!-- Regenerate the href here, to ensure it accurately points to correct location, including chunk filename) -->
345355
<xsl:attribute name="href">
346356
<xsl:call-template name="href.target">

htmlbook-xsl/common.xsl

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,8 +466,8 @@
466466
</xsl:when>
467467
<xsl:when test="$node[self::h:aside]">
468468
<xsl:choose>
469-
<xsl:when test="@data-type">
470-
<xsl:value-of select="@data-type"/>
469+
<xsl:when test="$node[@data-type]">
470+
<xsl:value-of select="$node/@data-type"/>
471471
</xsl:when>
472472
<xsl:otherwise>sidebar</xsl:otherwise>
473473
</xsl:choose>
@@ -618,4 +618,66 @@
618618
<!-- Default rule for PDF bookmarks; do nothing for elements that aren't sections or Part divs -->
619619
<xsl:template match="*" mode="pdf-bookmark"/>
620620

621+
<!-- Templates for handling of class values -->
622+
<xsl:template match="*" mode="class.attribute">
623+
<xsl:param name="xref.elements.pagenum.in.class" select="$xref.elements.pagenum.in.class"/>
624+
<xsl:param name="xref.target"/>
625+
<xsl:param name="class" select="@class"/>
626+
<xsl:variable name="class.value">
627+
<xsl:apply-templates select="." mode="class.value">
628+
<xsl:with-param name="class" select="$class"/>
629+
<xsl:with-param name="xref.elements.pagenum.in.class" select="$xref.elements.pagenum.in.class"/>
630+
<xsl:with-param name="xref.target" select="$xref.target"/>
631+
</xsl:apply-templates>
632+
</xsl:variable>
633+
<xsl:if test="normalize-space($class.value) != ''">
634+
<xsl:attribute name="class">
635+
<xsl:value-of select="$class.value"/>
636+
</xsl:attribute>
637+
</xsl:if>
638+
</xsl:template>
639+
640+
<!-- Default is to use supplied $class param as @class value -->
641+
<xsl:template match="*" mode="class.value">
642+
<xsl:param name="class" select="@class"/>
643+
<xsl:param name="xref.elements.pagenum.in.class" select="$xref.elements.pagenum.in.class"/>
644+
<xsl:param name="xref.target"/>
645+
<xsl:value-of select="$class"/>
646+
</xsl:template>
647+
648+
<xsl:template match="h:a[@data-type='xref']" mode="class.value">
649+
<xsl:param name="class" select="@class"/>
650+
<xsl:param name="xref.elements.pagenum.in.class" select="$xref.elements.pagenum.in.class"/>
651+
<xsl:param name="xref.target"/>
652+
<xsl:choose>
653+
<!-- If there's an xref target, process that to determine whether a pagenum value should be added to the class -->
654+
<xsl:when test="$xref.target">
655+
<xsl:variable name="xref.target.semantic.name">
656+
<xsl:call-template name="semantic-name">
657+
<xsl:with-param name="node" select="$xref.target"/>
658+
</xsl:call-template>
659+
</xsl:variable>
660+
<xsl:if test="$class != ''">
661+
<xsl:value-of select="$class"/>
662+
</xsl:if>
663+
<!-- Check if target semantic name is in list of XREF elements containing pagenum -->
664+
<!-- ToDo: Consider modularizing logic into separate function if needed for reuse elsewhere -->
665+
<xsl:variable name="space-delimited-pagenum-elements" select="concat(' ', normalize-space($xref.elements.pagenum.in.class), ' ')"/>
666+
<xsl:variable name="substring-before-target-name" select="substring-before($space-delimited-pagenum-elements, $xref.target.semantic.name)"/>
667+
<xsl:variable name="substring-after-target-name" select="substring-after($space-delimited-pagenum-elements, $xref.target.semantic.name)"/>
668+
<!-- Make sure a match is both preceded and followed by a space -->
669+
<xsl:if test="substring($substring-after-target-name, 1, 1) and
670+
substring($substring-before-target-name, string-length($substring-before-target-name), 1)">
671+
<xsl:if test="$class != ''"><xsl:text> </xsl:text></xsl:if>
672+
<xsl:text>pagenum</xsl:text>
673+
</xsl:if>
674+
</xsl:when>
675+
<xsl:otherwise>
676+
<xsl:if test="$class != ''">
677+
<xsl:value-of select="$class"/>
678+
</xsl:if>
679+
</xsl:otherwise>
680+
</xsl:choose>
681+
</xsl:template>
682+
621683
</xsl:stylesheet>

htmlbook-xsl/param.xsl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,17 @@ sect5:xref
160160
<!-- When set to 1, add a <div> within a <figure> to encapsulate all the non-caption <figure> content (to facilitate styling) -->
161161
<xsl:param name="figure.border.div" select="0"/>
162162

163+
<!-- Params around page numeration -->
164+
165+
<!-- Add a class of "pagenum" to XREFs pointing to element in the supplied list -->
166+
<!-- Element names correspond to values produced by "semantic-name" template in common.xsl -->
167+
<xsl:param name="xref.elements.pagenum.in.class">
168+
sect1
169+
sect2
170+
sect3
171+
sect4
172+
sect5
173+
sidebar
174+
</xsl:param>
175+
163176
</xsl:stylesheet>

htmlbook-xsl/xrefgen.xsl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
<!-- All XREFs must be tagged with a @data-type containing XREF -->
1717
<xsl:template match="h:a[contains(@data-type, 'xref')]" name="process-as-xref">
1818
<xsl:param name="autogenerate-xrefs" select="$autogenerate-xrefs"/>
19+
<xsl:param name="xref.elements.pagenum.in.class" select="$xref.elements.pagenum.in.class"/>
20+
1921
<xsl:variable name="calculated-output-href">
2022
<xsl:call-template name="calculate-output-href">
2123
<xsl:with-param name="source-href-value" select="@href"/>
@@ -36,9 +38,13 @@
3638
<!-- Generate XREF text node if $autogenerate-xrefs is enabled -->
3739
<xsl:when test="($autogenerate-xrefs = 1) and ($is-xref = 1)">
3840
<xsl:choose>
39-
<!-- If we can locate the target, process gentext with "xref-to" -->
41+
<!-- If we can locate the target, reprocess class attribute to add "pagenum" if needed, and process gentext with "xref-to" -->
4042
<xsl:when test="count(key('id', $href-anchor)) > 0">
4143
<xsl:variable name="target" select="key('id', $href-anchor)[1]"/>
44+
<xsl:apply-templates select="." mode="class.attribute">
45+
<xsl:with-param name="xref.elements.pagenum.in.class" select="$xref.elements.pagenum.in.class"/>
46+
<xsl:with-param name="xref.target" select="$target"/>
47+
</xsl:apply-templates>
4248
<xsl:apply-templates select="$target" mode="xref-to">
4349
<xsl:with-param name="referrer" select="."/>
4450
<xsl:with-param name="xrefstyle" select="@data-xrefstyle"/>

htmlbook-xsl/xspec/chunk.xspec

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
<!-- Globally setting url.in.parens to 0 here; tests for url.in.parens handling below modify param value on a oneoff basis -->
1212
<x:param name="url.in.parens" select="0"/>
1313

14+
<!-- Globally setting xref.elements.pagenum.in.class to be empty here; specific tests for pagenum class handling below modify param value on a oneoff basis -->
15+
<x:param name="xref.elements.pagenum.in.class"/>
16+
1417
<!-- Tests around text nodes for formal XREF elements (those with data-type='xref') -->
1518
<x:scenario label="When *empty* XREF element is matched">
1619
<x:context select="(//h:section//h:a[@data-type='xref'])[1]">
@@ -455,6 +458,76 @@
455458
</x:scenario>
456459
</x:scenario>
457460

461+
<!-- Tests around "pagenum" classes for XREFs -->
462+
<x:scenario label="If XREF is matched">
463+
<x:context>
464+
<body>
465+
<section data-type="chapter" id="first">
466+
<h1>First chapter</h1>
467+
<p>Some text</p>
468+
<p>XREF to second chapter is here: see <a id="chapter_xref" data-type="xref" href="#second"/></p>
469+
<p>Now here's a sidebar:</p>
470+
<aside data-type="sidebar" id="sidebar">
471+
<h5>Sidebar heading</h5>
472+
<p>Sidebar text</p>
473+
</aside>
474+
<p>XREF to the sect1 in second chapter: see <a id="sect1_xref" data-type="xref" href="#chapter2_sect1"/></p>
475+
</section>
476+
<section data-type="chapter" id="second">
477+
<h1>Second chapter</h1>
478+
<p>Let's add a sect1</p>
479+
<section data-type="sect1" id="chapter2_sect1">
480+
<h1>Subsection heading</h1>
481+
<p>Always soft-code your cross-references</p>
482+
<p>Like this one to the sidebar in the previous chapter: see <a class="underline" id="sidebar_xref" data-type="xref" href="#sidebar"/></p>
483+
</section>
484+
</section>
485+
</body>
486+
</x:context>
487+
488+
<x:scenario label="that points to an element in the xref.elements.pagenum.in.class list">
489+
<x:context select="//h:a[@data-type='xref'][@id='chapter_xref']">
490+
<x:param name="xref.elements.pagenum.in.class">chapter
491+
sidebar
492+
</x:param>
493+
</x:context>
494+
<x:expect label="Class value of 'pagenum' should be added to element" test="exists(//h:a[@class = 'pagenum'])"/>
495+
</x:scenario>
496+
497+
<x:scenario label="that points to an element in the xref.elements.pagenum.in.class list (XREF already has class value)">
498+
<x:context select="//h:a[@data-type='xref'][@id='sidebar_xref']">
499+
<x:param name="xref.elements.pagenum.in.class">chapter
500+
sidebar
501+
</x:param>
502+
</x:context>
503+
<x:expect label="Class value of 'pagenum' should be added to element (preserving existing class values)" test="exists(//h:a[@class = 'underline pagenum'])"/>
504+
</x:scenario>
505+
506+
<x:scenario label="that points to an element *not in* the xref.elements.pagenum.in.class list">
507+
<x:context select="//h:a[@data-type='xref'][@id='sect1_xref']">
508+
<x:param name="xref.elements.pagenum.in.class">chapter
509+
sidebar
510+
</x:param>
511+
</x:context>
512+
<x:expect label="Class value of 'pagenum' should not be added to element" test="not(exists(//h:a[@class = 'pagenum']))"/>
513+
</x:scenario>
514+
515+
<x:scenario label="with xref.elements.pagenum.in.class empty and no preexisting class on XREF">
516+
<x:context select="//h:a[@data-type='xref'][@id='chapter_xref']">
517+
<x:param name="xref.elements.pagenum.in.class"/>
518+
</x:context>
519+
<x:expect label="No class attribute should be added to element" test="not(exists(//h:a[@class]))"/>
520+
</x:scenario>
521+
522+
<x:scenario label="with xref.elements.pagenum.in.class empty and a preexisting class on XREF">
523+
<x:context select="//h:a[@data-type='xref'][@id='sidebar_xref']">
524+
<x:param name="xref.elements.pagenum.in.class"/>
525+
</x:context>
526+
<x:expect label="Class attribute should be preserved as is" test="exists(//h:a[@class='underline'])"/>
527+
</x:scenario>
528+
529+
</x:scenario>
530+
458531
<x:pending>
459532
<!-- Make sure there are some href tests with XREFs that are intra-chunk -->
460533
<!-- Possible to get this block working within XSpec? Currently getting the right results when

htmlbook-xsl/xspec/common.xspec

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,4 +948,97 @@ sect5:none
948948
<x:expect label="The caption content should contain a label" test="exists(//h:figcaption[h:span[@class='label' and contains(., 'Figure 1')]]) and contains(//h:figcaption[1], 'Touch this caption!')"/>
949949
</x:scenario>
950950

951+
<!-- class.attribute handling -->
952+
<x:pending>
953+
<!-- Not sure XSpec can handle tests that generate just an attribute node, e.g.:
954+
XTDE0420: Cannot create an attribute node (class) whose parent is a document node
955+
-->
956+
<x:scenario label="If an element is matched in class.attribute modee">
957+
<x:context mode="class.attribute"/>
958+
959+
<x:scenario label="and its generated class attribute (via class.value) is empty">
960+
<x:context>
961+
<section data-type="chapter"/>
962+
</x:context>
963+
<x:expect label="No @class should be generated" test="not(exists(//@class))"/>
964+
</x:scenario>
965+
966+
<x:scenario label="and its generated class attribute (via class.value) is non empty">
967+
<x:context>
968+
<section data-type="chapter" class="case-study"/>
969+
</x:context>
970+
<x:expect label="@class should be generated" test="exists(//@class)"/>
971+
</x:scenario>
972+
</x:scenario>
973+
</x:pending>
974+
975+
<!-- class.value handling -->
976+
<x:scenario label="If XREF is matched in class.value mode">
977+
<x:context mode="class.value">
978+
<body>
979+
<section data-type="chapter" id="first">
980+
<h1>First chapter</h1>
981+
<p>Some text</p>
982+
<p>XREF to second chapter is here: see <a id="chapter_xref" data-type="xref" href="#second"/></p>
983+
<p>Now here's a sidebar:</p>
984+
<aside data-type="sidebar" id="sidebar">
985+
<h5>Sidebar heading</h5>
986+
<p>Sidebar text</p>
987+
</aside>
988+
<p>XREF to the sect1 in second chapter: see <a id="sect1_xref" data-type="xref" href="#chapter2_sect1"/></p>
989+
</section>
990+
<section data-type="chapter" id="second">
991+
<h1>Second chapter</h1>
992+
<p>Let's add a sect1</p>
993+
<section data-type="sect1" id="chapter2_sect1">
994+
<h1>Subsection heading</h1>
995+
<p>Always soft-code your cross-references</p>
996+
<p>Like this one to the sidebar in the previous chapter: see <a class="underline" id="sidebar_xref" data-type="xref" href="#sidebar"/></p>
997+
</section>
998+
</section>
999+
</body>
1000+
</x:context>
1001+
1002+
<x:scenario label="that points to an element in the xref.elements.pagenum.in.class list">
1003+
<x:context select="//h:a[@data-type='xref'][@id='chapter_xref']">
1004+
<x:param name="xref.elements.pagenum.in.class">chapter
1005+
sidebar
1006+
</x:param>
1007+
<x:param name="xref.target" select="//*[@id='second']"/>
1008+
</x:context>
1009+
<x:expect label="Class value of 'pagenum' should be returned">pagenum</x:expect>
1010+
</x:scenario>
1011+
1012+
<x:scenario label="that points to an element in the xref.elements.pagenum.in.class list (XREF already has class value)">
1013+
<x:context select="//h:a[@data-type='xref'][@id='sidebar_xref']">
1014+
<x:param name="xref.elements.pagenum.in.class">chapter
1015+
sidebar
1016+
</x:param>
1017+
<x:param name="xref.target" select="//h:aside[@id='sidebar']"/>
1018+
</x:context>
1019+
<x:expect label="Class value of 'pagenum' should be appended to existing class value list">underline pagenum</x:expect>
1020+
</x:scenario>
1021+
1022+
<x:scenario label="that points to an element *not in* the xref.elements.pagenum.in.class list (no existing class)">
1023+
<x:context select="//h:a[@data-type='xref'][@id='sect1_xref']">
1024+
<x:param name="xref.elements.pagenum.in.class">chapter
1025+
sidebar
1026+
</x:param>
1027+
<x:param name="xref.target" select="//*[@id='chapter2_sect1']"/>
1028+
</x:context>
1029+
<x:expect label="Class value of 'pagenum' should not be added. Returned value should be empty" select="()"/>
1030+
</x:scenario>
1031+
1032+
<x:scenario label="that points to an element *not in* the xref.elements.pagenum.in.class list (XREF already has class value)">
1033+
<x:context select="//h:a[@data-type='xref'][@id='sidebar_xref']">
1034+
<x:param name="xref.elements.pagenum.in.class">chapter
1035+
sect1
1036+
</x:param>
1037+
<x:param name="xref.target" select="//*[@id='sidebar']"/>
1038+
</x:context>
1039+
<x:expect label="Class value of 'pagenum' *should not* be added. Class value preserved as is">underline</x:expect>
1040+
</x:scenario>
1041+
1042+
</x:scenario>
1043+
9511044
</x:description>

0 commit comments

Comments
 (0)