Skip to content

Commit e76491d

Browse files
author
Sanders Kleinfeld
committed
Merge pull request #141 from oreillymedia/pagenums
Parameterized handling for "pagenum" classes for print outputs
2 parents be8ce8c + 6785ca3 commit e76491d

File tree

7 files changed

+339
-9
lines changed

7 files changed

+339
-9
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: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -267,17 +267,17 @@
267267
<xsl:template name="get-param-value-from-key">
268268
<xsl:param name="parameter"/>
269269
<xsl:param name="key"/>
270-
<xsl:variable name="entry-and-beyond-for-data-type">
271-
<!-- Gets the config line for numeration for the specified data-type...and everything beyond -->
270+
<xsl:variable name="entry-and-beyond">
271+
<!-- Gets the value corresponding to specified key...and everything beyond -->
272272
<xsl:value-of select="substring-after(normalize-space($parameter), concat($key, ':'))"/>
273273
</xsl:variable>
274-
<!-- Then we further narrow to the exact numeration format type -->
274+
<!-- Then we further narrow to just the key value -->
275275
<xsl:choose>
276-
<xsl:when test="contains($entry-and-beyond-for-data-type, ' ')">
277-
<xsl:value-of select="substring-before($entry-and-beyond-for-data-type, ' ')"/>
276+
<xsl:when test="contains($entry-and-beyond, ' ')">
277+
<xsl:value-of select="substring-before($entry-and-beyond, ' ')"/>
278278
</xsl:when>
279279
<xsl:otherwise>
280-
<xsl:value-of select="$entry-and-beyond-for-data-type"/>
280+
<xsl:value-of select="$entry-and-beyond"/>
281281
</xsl:otherwise>
282282
</xsl:choose>
283283
</xsl:template>
@@ -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)