Newer
Older
XML / modules / basic-page-elements.xml
<?xml version="1.0" encoding="utf-8"?>

<!--
	Basic page layout elements, like paragraphs, page breaks, etc.
-->

<stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


	<!--
		Plain paragraph.
		
		@indent: Whether or not to indent this paragraph (probably only relevant in LaTeX).
			'no' => don't indent.
			otherwise => apply standard paragraph formatting. [default]
		
		@align: How to align the paragraph. Note that these are potentially distinct from the default action, e.g., specifying align="left" will produce a flushleft environment in LaTeX, which is a different effect from not specifying an alignment at all.
			'left' => left alignment
			'center' => centered alignment
			'right' => right alignment
			otherwise => apply standard paragraph formatting. [default]

		@border: Whether or not to draw a border around the paragraph.
			'yes' => draw a border.
			otherwise => apply standard paragraph formatting. [default]
	-->
	<template name="paragraph" match="paragraph|para|p|P">
		<common formats="/latex/xelatex/">
			<!--
				LaTeX delimits paragraphs with vertical whitespace, so we need to ensure plenty. A couple of blank lines before and after should be sufficient.
			-->
			<xsl:call-template name="newline-internal" />
			<xsl:call-template name="newline-internal" />
			<xsl:choose>
				<xsl:when test="@align = ('left', 'right')">
					<xsl:text>\begin{flush</xsl:text>
					<xsl:value-of select="@align" />
					<xsl:text>}</xsl:text>
				</xsl:when>
				<xsl:when test="@align = ('center', 'centre')">
					<xsl:text>\begin{center}</xsl:text>
				</xsl:when>
			</xsl:choose>
			<xsl:if test="@indent = ('no', 'n', 'false', 'f', '0')">
				<xsl:text>\noindent </xsl:text>
			</xsl:if>
			<xsl:if test="@border = ('yes', 'y')">
			    <!-- Adjust box to fit relevant text margins. -->
			    <xsl:text>\hspace*{-\fboxsep}</xsl:text>
                <xsl:text>\setlength{\parwidth}{\textwidth}</xsl:text>
			    <xsl:if test="ancestor::item">
                    <xsl:text>\addtolength{\parwidth}{-\leftmargin}</xsl:text>
                    <xsl:text>\addtolength{\parwidth}{-\rightmargin}</xsl:text>
                </xsl:if>
				<xsl:text>\fbox{\parbox[t]{\parwidth}{</xsl:text>
			</xsl:if>
			<xsl:apply-templates />
			<xsl:if test="@border = ('yes', 'y')">
				<xsl:text>}}</xsl:text>
			</xsl:if>
			<xsl:choose>
				<xsl:when test="@align = ('left', 'right')">
					<xsl:text>\end{flush</xsl:text>
					<xsl:value-of select="@align" />
					<xsl:text>}</xsl:text>
				</xsl:when>
				<xsl:when test="@align = ('center', 'centre')">
					<xsl:text>\end{center}</xsl:text>
				</xsl:when>
			</xsl:choose>
			<xsl:call-template name="newline-internal" />
			<xsl:call-template name="newline-internal" />
		</common>
		<!--
			HTML is weird about what things you cannot include inside paragraphs (e.g. lists of any kind). However, the end P tag is optional, so one option might simply be not to output it (not for XHTML, though!).
		-->
		<common formats="/html/xhtml/">
			<!--
				The HTMLStyle parameter is an Ugly Hack(tm) to ensure that paragraphs are indented correctly inside definition lists in HTML. I tried modes first, but they didn't work correctly. Fortunately this only needs to be done with paragraphs, so this will work fine.
			-->
			<xsl:param name="HTMLStyle" />
			<p>
                <xsl:if test="@border = ('yes', 'y')">
					<xsl:attribute name="style">border: 1px solid black;</xsl:attribute>
				</xsl:if>
				<xsl:if test="$HTMLStyle">
					<xsl:attribute name="class">
						<xsl:value-of select="$HTMLStyle" />
					</xsl:attribute>
				</xsl:if>
				<xsl:if test="@align">
					<xsl:attribute name="align">
						<xsl:value-of select="@align" />
					</xsl:attribute>
				</xsl:if>
				<xsl:apply-templates />
			</p>
		</common>
	</template>
	
	
	<!-- New line. -->
	
	<template name="newline" match="newline|line-break|br">
		<common formats="/latex/xelatex/">
			<xsl:text> \\</xsl:text>
			<xsl:call-template name="newline-internal" />
		</common>
		<common formats="/html/xhtml/">
			<br />
		</common>
	</template>

	<!--
		Whereas the "newline" template above is for line breaks intended to be displayed in the final document, this is for additional linebreaks in the generated LaTeX or HTML markup. This is used to avoid things like "\end{verbatim}\item" all on one line, not that this really matters in general, as the generated markup will be pretty messy anyway, and TeX doesn't usually care :).
		
		This also makes any XSLT markup that generates internal newlines a lot tidier looking!
	-->
	<template name="newline-internal" match="newline-internal">
		<common>
			<xsl:text>
</xsl:text>
		</common>
	</template>
	
	
	<!--
		Text that shouldn't be broken across a line (i.e., LaTeX \mbox).
		Only really relevant for LaTeX because we can't control this in HTML.
	-->
	<template name="no-break" match="no-break|mbox">
		<common formats="/latex/xelatex/">
			<xsl:text>\mbox{</xsl:text>
			<xsl:apply-templates />
			<xsl:text>}</xsl:text>
		</common>
		<common formats="/html/xhtml/">
			<xsl:apply-templates />
		</common>
	</template>
	
	
	<!--
		Page break. This is only relevant for LaTeX formats at present.
		
		The page break is automatically suppressed if the parent node is "answer" and $showanswers is "no", or the parent node is "question" and $showanswers is "yes". This is to prevent page breaks that look fine in one but not the other.
		If you want to force a page break regardless, put after the "answer" element for a question item.
		
		@print-caption: Whether or not to print a caption before the page break.
			'yes' => display the caption
			otherwise => display nothing [default]
		
		@caption-text: The text to be printed before the page break. The default is "continues over...".
	-->
	
	<template name="page-break" match="page-break|new-page|newpage|pagebreak">
		<common formats="/latex/xelatex/">
            <xsl:variable name="insert" select="
                if ((name(..) eq 'answer') and ($showanswers = ('no', 'n', 'false', 'f', '0'))) then false()
                else if ((name(..) eq 'question') and ($showanswers = ('yes', 'y', 'true', 't', '1'))) then false()
                else true()" />
            <xsl:if test="$insert">
                <xsl:if test="@print-caption = ('yes', 'y', 'true', 't', '1')">
                    <xsl:text>\begin{flushright}</xsl:text>
                    <xsl:call-template name="newline-internal" />
                    <xsl:text>\emph{</xsl:text>
                    <xsl:choose>
                        <xsl:when test="@caption-text">
                            <xsl:value-of select="@caption-text" />
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:text>continues over\ldots</xsl:text>
                        </xsl:otherwise>
                    </xsl:choose>
                    <xsl:text>}</xsl:text>
                    <xsl:call-template name="newline-internal" />
                    <xsl:text>\end{flushright}</xsl:text>
                    <xsl:call-template name="newline-internal" />
                </xsl:if>
                <xsl:text>\newpage</xsl:text>
                <xsl:call-template name="newline-internal" />
            </xsl:if>
		</common>
	</template>
	
	
	<!--
		Skip a certain amount of space vertically. Probably more relevant to LaTeX than HTML. Is it even possible to vskip a set amount in HTML?? I suppose you could create an empty <div> element with a specified height, but I'm not sure that it even makes sense in HTML to skip more than the standard paragraph separation anyway.
		
		@size: the amount of space to skip.
			missing => \vskip\baselineskip [default]
			'small' => \smallskip
			'medium' => \medskip
			'large' => \bigskip
			'fill' => \vfill
			LaTeX length => \vskipxx
	-->
	<template name="vertical-skip" match="vertical-skip|vskip">
		<common formats="/latex/xelatex/">
			<xsl:choose>
				<xsl:when test="not(@size)">
					<xsl:text>\vskip\baselineskip</xsl:text>
				</xsl:when>
				<xsl:when test="@size='small'">
					<xsl:text>\smallskip</xsl:text>
				</xsl:when>
				<xsl:when test="@size='medium'">
					<xsl:text>\medskip</xsl:text>
				</xsl:when>
				<xsl:when test="@size='large'">
					<xsl:text>\bigskip</xsl:text>
				</xsl:when>
				<xsl:when test="@size='fill'">
					<xsl:text>\vfill</xsl:text>
				</xsl:when>
				<!-- Check for valid LaTeX length format, e.g., "2.54cm". -->
				<xsl:when test="matches( @size, '^\d*\.?\d+(cm|em|ex|in|pc|pt|mm|bp)$' )">
					<xsl:text>\vskip</xsl:text>
					<xsl:value-of select="@size" />
				</xsl:when>
				<xsl:otherwise>
					<xsl:message terminate="yes">
						<xsl:text>Invalid vertical skip expression for LaTeX: "</xsl:text>
						<xsl:value-of select="@size" />
						<xsl:text>" (valid values are "small", "medium", "large", "fill", or a LaTeX length, e.g., "24pt")</xsl:text>
					</xsl:message>
				</xsl:otherwise>
			</xsl:choose>
			<xsl:call-template name="newline-internal" />
		</common>
		<common formats="/html/xhtml/">
			<!-- For the moment we'll just throw in a <br /> :). -->
			<br clear="left" />
		</common>
	</template>
	
	
	<!--
		Skip a certain amount of space horizontally. Probably more relevant to LaTeX than HTML. Is it even possible to hskip a set amount in HTML?? I suppose you could create an empty <span> element with a specified width.
		
		@size: the amount of space to skip.
			missing => ERROR [default]
			'fill' => \hfill
			LaTeX length => \hskipxx
	-->
	<template name="horizontal-skip" match="horizontal-skip|hskip">
		<common formats="/latex/xelatex/">
			<xsl:choose>
				<xsl:when test="@size='fill'">
					<xsl:text>\hfill</xsl:text>
				</xsl:when>
				<!-- Check for valid LaTeX length format, e.g., "2.54cm". -->
				<xsl:when test="matches( @size, '^\d*\.?\d+(cm|em|ex|in|pc|pt|mm|bp)$' )">
					<xsl:text>\hskip</xsl:text>
					<xsl:value-of select="@size" />
				</xsl:when>
				<xsl:otherwise>
					<xsl:message terminate="yes">
						<xsl:text>Invalid horizontal skip expression for LaTeX: "</xsl:text>
						<xsl:value-of select="@size" />
						<xsl:text>" (must either be "fill" or a LaTeX length, e.g., "24pt")</xsl:text>
					</xsl:message>
				</xsl:otherwise>
			</xsl:choose>
			<xsl:call-template name="newline-internal" />
		</common>
		<common formats="/html/xhtml/">
			<!-- For the moment we'll just ignore this for (X)HTML :). -->
		</common>
	</template>
	
	
	<!--
	    Generate a horizontal rule the width of the column.
	-->
	<template name="horizontal-rule" match="horizontal-rule|hrule|hr">
		<common formats="/latex/xelatex/">
		    <xsl:text>\hrule</xsl:text>
			<xsl:call-template name="newline-internal" />
		</common>
		<common formats="/html/xhtml/">
		    <xsl:element name="hr" />
		</common>
	</template>

	
</stylesheet>