end
end
+ it "should include one and only one <h1> in each HTML file in rendered ePub files for <book>s" do
+ begin
+ tmpdir = File.join(Dir::tmpdir(), "epubtoctest"); Dir.mkdir(tmpdir) rescue Errno::EEXIST
+
+ epub = DocBook::Epub.new(File.join(@testdocsdir, "book.002.xml"), @tmpdir)
+ epubfile = File.join(tmpdir, "h1count.epub")
+ epub.render_to_file(epubfile, $DEBUG)
+ FileUtils.copy(epubfile, ".h1c.epub") if $DEBUG
+
+ success = system("unzip -q -d #{File.expand_path(tmpdir)} -o #{epubfile}")
+ raise "Could not unzip #{epubfile}" unless success
+ glob = Dir.glob(File.join(tmpdir, "**", "*.html"))
+ glob.each {|html_file|
+ h1s = File.open(html_file).readlines.to_s.scan(/<h1/)
+ puts html_file if $DEBUG && h1s.length != 1
+ h1s.length.should == 1
+ }
+ rescue => e
+ raise e
+ ensure
+ FileUtils.rm_r(tmpdir, :force => true)
+ end
+ end
+
+ it "should include one and only one <h1> in each HTML file in rendered ePub files for <book>s even if they do not have section markup" do
+ begin
+ tmpdir = File.join(Dir::tmpdir(), "epubtoctest"); Dir.mkdir(tmpdir) rescue Errno::EEXIST
+
+ epub = DocBook::Epub.new(File.join(@testdocsdir, "book.002.xml"), @tmpdir)
+ epubfile = File.join(tmpdir, "h1count2.epub")
+ epub.render_to_file(epubfile, $DEBUG)
+ FileUtils.copy(epubfile, ".h1c2.epub") if $DEBUG
+
+ success = system("unzip -q -d #{File.expand_path(tmpdir)} -o #{epubfile}")
+ raise "Could not unzip #{epubfile}" unless success
+ glob = Dir.glob(File.join(tmpdir, "**", "*.html"))
+ glob.each {|html_file|
+ h1s = File.open(html_file).readlines.to_s.scan(/<h1/)
+ puts html_file if $DEBUG && h1s.length != 1
+ h1s.length.should == 1
+ }
+ rescue => e
+ raise e
+ ensure
+ FileUtils.rm_r(tmpdir, :force => true)
+ end
+ end
+
it "should include a TOC link in rendered epub files for <book>s" do
begin
tmpdir = File.join(Dir::tmpdir(), "epubtoctest"); Dir.mkdir(tmpdir) rescue Errno::EEXIST
</xsl:template>
+<!-- Change section.heading to improve SEO on generated HTML by doing heading levels
+ "correctly". SEO rules are sometimes silly silly, but this does actually create
+ a semantic improvement.
+ Note: This template needs to be manually maintained outside of the html/sections.xsl
+ code, so make sure important changes get reintegrated. -->
+<xsl:template name="section.heading">
+ <xsl:param name="section" select="."/>
+ <xsl:param name="level" select="1"/>
+ <xsl:param name="allow-anchors" select="1"/>
+ <xsl:param name="title"/>
+ <xsl:param name="class" select="'title'"/>
+
+ <xsl:variable name="id">
+ <xsl:choose>
+ <!-- Make sure the subtitle doesn't get the same id as the title -->
+ <xsl:when test="self::subtitle">
+ <xsl:call-template name="object.id">
+ <xsl:with-param name="object" select="."/>
+ </xsl:call-template>
+ </xsl:when>
+ <!-- if title is in an *info wrapper, get the grandparent -->
+ <xsl:when test="contains(local-name(..), 'info')">
+ <xsl:call-template name="object.id">
+ <xsl:with-param name="object" select="../.."/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="object.id">
+ <xsl:with-param name="object" select=".."/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <!-- For SEO, we try to actually ensure we *always* output one and only one h1,
+ so unlike the regular stylesheets, we don't add one to the section level and
+ we get the right behavior because of chunking. -->
+ <xsl:variable name="hlevel">
+ <xsl:choose>
+ <!-- highest valid HTML H level is H6; so anything nested deeper
+ than 7 levels down just becomes H6 -->
+ <xsl:when test="$level > 6">6</xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$level"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:element name="h{$hlevel}" namespace="http://www.w3.org/1999/xhtml">
+ <xsl:attribute name="class"><xsl:value-of select="$class"/></xsl:attribute>
+ <xsl:if test="$css.decoration != '0'">
+ <xsl:if test="$hlevel<3">
+ <xsl:attribute name="style">clear: both</xsl:attribute>
+ </xsl:if>
+ </xsl:if>
+ <xsl:if test="$allow-anchors != 0 and $generate.id.attributes = 0">
+ <xsl:call-template name="anchor">
+ <xsl:with-param name="node" select="$section"/>
+ <xsl:with-param name="conditional" select="0"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="$generate.id.attributes != 0 and not(local-name(.) = 'appendix')">
+ <xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
+ </xsl:if>
+ <xsl:copy-of select="$title"/>
+ </xsl:element>
+</xsl:template>
+
+<!-- ==================================================================== -->
+
+<xsl:template match="bridgehead">
+ <xsl:variable name="container" select="(ancestor::appendix |ancestor::article |ancestor::bibliography |ancestor::chapter |ancestor::glossary |ancestor::glossdiv |ancestor::index |ancestor::partintro |ancestor::preface |ancestor::refsect1 |ancestor::refsect2 |ancestor::refsect3 |ancestor::sect1 |ancestor::sect2 |ancestor::sect3 |ancestor::sect4 |ancestor::sect5 |ancestor::section |ancestor::setindex |ancestor::simplesect)[last()]"/>
+
+ <xsl:variable name="clevel">
+ <xsl:choose>
+ <xsl:when test="local-name($container) = 'appendix' or local-name($container) = 'chapter' or local-name($container) = 'article' or local-name($container) = 'bibliography' or local-name($container) = 'glossary' or local-name($container) = 'index' or local-name($container) = 'partintro' or local-name($container) = 'preface' or local-name($container) = 'setindex'">1</xsl:when>
+ <xsl:when test="local-name($container) = 'glossdiv'">
+ <xsl:value-of select="count(ancestor::glossdiv)+1"/>
+ </xsl:when>
+ <xsl:when test="local-name($container) = 'sect1' or local-name($container) = 'sect2' or local-name($container) = 'sect3' or local-name($container) = 'sect4' or local-name($container) = 'sect5' or local-name($container) = 'refsect1' or local-name($container) = 'refsect2' or local-name($container) = 'refsect3' or local-name($container) = 'section' or local-name($container) = 'simplesect'">
+ <xsl:variable name="slevel">
+ <xsl:call-template name="section.level">
+ <xsl:with-param name="node" select="$container"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="$slevel + 1"/>
+ </xsl:when>
+ <xsl:otherwise>1</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <!-- HTML H level is one higher than section level -->
+ <xsl:variable name="hlevel">
+ <xsl:choose>
+ <xsl:when test="@renderas = 'sect1'">1</xsl:when>
+ <xsl:when test="@renderas = 'sect2'">2</xsl:when>
+ <xsl:when test="@renderas = 'sect3'">3</xsl:when>
+ <xsl:when test="@renderas = 'sect4'">4</xsl:when>
+ <xsl:when test="@renderas = 'sect5'">5</xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$clevel + 1"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:element name="h{$hlevel}" namespace="http://www.w3.org/1999/xhtml">
+ <xsl:call-template name="anchor">
+ <xsl:with-param name="conditional" select="0"/>
+ </xsl:call-template>
+ <xsl:apply-templates/>
+ </xsl:element>
+</xsl:template>
+
+<!-- SEO customization #2 -->
+<xsl:template name="component.title">
+ <xsl:param name="node" select="."/>
+
+ <xsl:variable name="level">
+ <xsl:choose>
+ <xsl:when test="ancestor::section">
+ <xsl:value-of select="count(ancestor::section)+1"/>
+ </xsl:when>
+ <xsl:when test="ancestor::sect5">6</xsl:when>
+ <xsl:when test="ancestor::sect4">5</xsl:when>
+ <xsl:when test="ancestor::sect3">4</xsl:when>
+ <xsl:when test="ancestor::sect2">3</xsl:when>
+ <xsl:when test="ancestor::sect1">2</xsl:when>
+ <xsl:otherwise>1</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:element name="h{$level}" namespace="http://www.w3.org/1999/xhtml">
+ <xsl:attribute name="class">title</xsl:attribute>
+ <xsl:if test="$generate.id.attributes = 0">
+ <xsl:call-template name="anchor">
+ <xsl:with-param name="node" select="$node"/>
+ <xsl:with-param name="conditional" select="0"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:apply-templates select="$node" mode="object.title.markup">
+ <xsl:with-param name="allow-anchors" select="1"/>
+ </xsl:apply-templates>
+ </xsl:element>
+</xsl:template>
+
</xsl:stylesheet>