+<!--
+ Nokogiri's pretty-printer is a bit weird. Regardless of the indentation
+ setting, if an element has no child text nodes then it will be pretty-
+ printed. This works by adding arbitrary whitespace to that element, and
+ then all of its children are eligible to be pretty-printed.
+
+ If an element has any text nodes at all, then it is not pretty-printed and
+ neither are any of its descendents.
+
+ Adding arbitrary whitespace to <pre> is bad, so we inject zero-width non-
+ breaking spaces to prevent this. This will render fine but the spaces
+ should be removed before final output to avoid problems with copy+paste.
+-->
+<xsl:template match='xhtml:pre'>
+ <xsl:copy>
+ <xsl:apply-templates select='node()|@*' />
+ <xsl:text>⁠</xsl:text>
+ </xsl:copy>
+</xsl:template>
+
+<!--
+ Likewise, adding spaces between consecutive span-level elements where
+ none existed before won't go over well.
+-->
+<xsl:template name='glue-preceding-span'>
+ <xsl:if test='f:element-is-span(preceding-sibling::node()[1])'>
+ <xsl:text>⁠</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match='*[f:element-is-span()]'>
+ <xsl:call-template name='glue-preceding-span' />
+ <xsl:copy>
+ <xsl:apply-templates select='node()|@*' />
+ <xsl:if test='*'>
+ <!-- avoid breaking within a span element -->
+ <xsl:text>⁠</xsl:text>
+ </xsl:if>
+ </xsl:copy>
+</xsl:template>
+
+<!--
+ Manually strip whitespace-only text nodes so the pretty printer can do its
+ thing on remaining elements.
+-->
+<xsl:template match='text()[normalize-space(.) = ""]'>
+ <xsl:choose>
+ <!-- preserve anything according to xml:space -->
+ <xsl:when test='ancestor::*[@xml:space][1][@xml:space="preserve"]'>
+ <xsl:copy />
+ </xsl:when>
+ <!-- preserve anything under <pre> -->
+ <xsl:when test='ancestor::xhtml:pre'><xsl:copy /></xsl:when>
+ <!-- preserve whitespace which is the only child node of an element -->
+ <xsl:when test='count(../node()) = 1'><xsl:copy /></xsl:when>
+ <!-- preserve whitespace between consecutive span-level elements
+ which have at least one non-whitespace sibling text element -->
+ <xsl:when test='f:element-is-span(preceding-sibling::node()[1])
+ and f:element-is-span(following-sibling::node()[1])
+ and ../text()[normalize-space(.) != ""]'>
+ <xsl:copy />
+ </xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+<!-- Clean up whitespace where harmless to do so -->
+<xsl:template match='xhtml:p/node()[1][self::text()]'>
+ <xsl:value-of select='f:strip-leading()' />
+</xsl:template>
+<xsl:template match='xhtml:p/node()[position()=last()][self::text()]'>
+ <xsl:value-of select='f:strip-trailing()' />
+</xsl:template>
+
+<!-- Add rel attributes to external links -->
+<xsl:template match='xhtml:a[starts-with(@href,"http://")
+ or starts-with(@href,"https://")
+ or starts-with(@href,"//")]'>
+ <xsl:variable name='domain'
+ select='substring-before(
+ concat(translate(substring-after(@href, "//"), ":", "/"), "/"),
+ "/")' />
+
+ <xsl:copy>
+ <xsl:apply-templates select='@*' />
+ <xsl:if test='not($domain="draconx.ca"
+ or f:ends-with($domain, ".draconx.ca"))'>
+ <xsl:attribute name='rel'>
+ <xsl:if test='@rel'>
+ <xsl:value-of select='@rel' />
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ <xsl:text>external noopener noreferrer</xsl:text>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates select='node()' />
+ </xsl:copy>
+</xsl:template>
+
+<xsl:template match='xhtml:h2[@id]'>
+ <xsl:variable name='fragment' select='concat("#", @id)' />
+ <xsl:copy>
+ <xsl:apply-templates select='node()|@*' />
+ <xsl:if test='$section-links = "yes"'>
+ <xsl:text> </xsl:text>
+ <small class='permalink'>
+ (<a href='{$fragment}'><xsl:value-of select='$fragment' /></a>)
+ </small>
+ </xsl:if>
+ </xsl:copy>
+</xsl:template>
+
+<!--
+ Convert caption attribute on tables into proper caption elements, to allow
+ a simple way to add captions to kramdown tables.
+-->
+<xsl:template match='@caption[parent::xhtml:table]' />
+<xsl:template match='xhtml:table[@caption]'>
+ <xsl:copy>
+ <xsl:apply-templates select='@*' />
+ <caption><xsl:value-of select='normalize-space(@caption)' /></caption>
+ <xsl:apply-templates select='node()' />
+ </xsl:copy>
+</xsl:template>
+
+<!--
+ Delete style elements, as they will get hoisted occur under <head> below.
+ If the generate-listing attribute was specified, produce a code listing
+ where the style attribute was found.
+-->
+<xsl:template match='xhtml:style|@generate-listing[parent::xhtml:style]' />
+<xsl:template match='xhtml:style[@generate-listing]'>
+ <pre>⁠<code><xsl:value-of select='f:strip-leading(.)' /></code></pre>
+</xsl:template>
+
+<!--
+ Add a simple way to reference a document node by ID and include the XHTML
+ code listing directly in the document.
+-->
+<xsl:template match='xhtml:generate-xhtml-listing'>
+ <xsl:variable name='target' select='@target' />
+ <pre>⁠<code>
+ <xsl:value-of select='f:xhtml-listing(//xhtml:*[@id=$target])' />
+ </code></pre>
+</xsl:template>
+
+<xsl:template match='copyright'>
+ <p>
+ <xsl:text>Copyright © </xsl:text>
+ <xsl:value-of select='text()' />
+ <xsl:text>.</xsl:text>
+ </p>
+</xsl:template>
+
+<xsl:template match='license'>
+ <p>
+ <xsl:text>Copying and distribution of this material</xsl:text>
+ <xsl:if test='normalize-space(modification-allowed)="yes"'>
+ <xsl:text>, with or without modification,</xsl:text>
+ </xsl:if>
+ <xsl:text> is permitted under the terms of the </xsl:text>
+ <a rel='license'>
+ <xsl:attribute name='href'>
+ <xsl:value-of select='normalize-space(uri)' />
+ </xsl:attribute>
+ <xsl:value-of select='name' />
+ </a>
+ <xsl:text>.</xsl:text>
+ </p>
+</xsl:template>
+
+<xsl:template match='source'>
+ <p>
+ <xsl:text>This document was compiled from </xsl:text>
+ <a href='{concat($source-uri, revision, ":", file)}'>
+ <xsl:value-of select='file' />
+ </a>
+ <xsl:text> on </xsl:text>
+ <xsl:value-of select='compiletime' />
+ <xsl:text>.</xsl:text>
+ </p>
+</xsl:template>
+
+<xsl:template match='xhtml:h1[not(preceding::xhtml:h1)]'>
+ <xsl:copy><xsl:apply-templates select='node()|@*' /></xsl:copy>
+ <xsl:if test='/document/article/published'>
+ <div id='article-info'>
+ <p>
+ <xsl:text>Posted </xsl:text>
+ <xsl:value-of select='/document/article/published' />
+ </p>
+ </div>
+ </xsl:if>
+</xsl:template>
+