
laika.render.epub.HtmlNavRenderer.scala Maven / Gradle / Ivy
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package laika.render.epub
import laika.ast.{NavigationItem, NavigationLink}
import laika.io.model.RenderedTreeRoot
import laika.render.TagFormatter
import laika.render.epub.StyleSupport.collectStylePaths
/** Renders the entire content of an EPUB HTML navigation file.
*
* @author Jens Halm
*/
class HtmlNavRenderer {
/** Inserts the specified (pre-rendered) navPoints into the NCX document template
* and returns the content of the entire NCX file.
*/
def fileContent (title: String, styles: String, navItems: String, coverDoc: Option[String] = None, titleDoc: Option[String] = None): String =
s"""
|
|
|
|
|
| $title
| $styles
|
|
|
|
|
|
""".stripMargin.replaceAll("[\n]+", "\n")
/** Renders a single navigation link.
*/
private def navLink (title: String, link: String, pos: Int, children: String): String =
s"""
| ${TagFormatter.escape(title)}
|$children
| """.stripMargin
/** Always use the link to the first child of a navigation header.
* Despite the fact that the EPUB spec supports "unlinked headers",
* which are just a `` element instead of an `` element,
* many e-book readers such as iBooks choke on them to the point of rendering navigation menus useless.
*
* Unlinked navigation headers are described in the EPUB spec here:
* https://www.w3.org/publishing/epub32/epub-packages.html#sec-package-nav-def-model
*/
private def linkOfFirstChild (children: Seq[NavigationItem]): NavigationLink =
children.head.link.getOrElse(linkOfFirstChild(children.head.content))
/** Generates navigation entries for the structure of the DocumentTree. Individual
* entries can stem from tree or subtree titles, document titles or
* document sections, depending on which recursion depth is configured.
* The configuration key for setting the recursion depth is `epub.toc.depth`.
*
* @param bookNav the navigation items to generate navPoints for
* @return the navPoint XML nodes for the specified document tree as a String
*/
private def navItems (bookNav: Seq[NavigationItem], pos: Iterator[Int] = Iterator.from(0)): String =
if (bookNav.isEmpty) ""
else bookNav.map { item =>
navLink(
item.title.extractText,
item.link.getOrElse(linkOfFirstChild(item.content)).target.render(),
pos.next(),
navItems(item.content, pos)
)
}.mkString(" \n", "\n", "\n
")
/** Renders the entire content of an EPUB HTML navigation file for
* the specified document tree. The recursion depth will be applied
* to the tree structure obtained by recursively processing titles of document
* trees, documents and sections.
* The configuration key for setting the recursion depth is `epub.toc.depth`.
*/
def render[F[_]] (result: RenderedTreeRoot[F], title: String, depth: Option[Int]): String = {
val bookNav = NavigationBuilder.forTree(result.tree, depth)
val styles = collectStylePaths(result).map { path =>
s""""""
}.mkString("\n ")
val renderedNavPoints = navItems(bookNav)
val coverDoc = result.coverDocument.map(doc => NavigationBuilder.fullPath(doc.path, forceXhtml = true))
val titleDoc = result.titleDocument.map(doc => NavigationBuilder.fullPath(doc.path, forceXhtml = true))
fileContent(title, styles, renderedNavPoints, coverDoc, titleDoc)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy