All Downloads are FREE. Search and download functionalities are using the official Maven repository.

laika.render.epub.NCXRenderer.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

/** Renders the entire content of an NCX navigation file.
  * These files will be ignored by EPUB 3 readers and are only
  * added for backwards-compatibility with older readers.
  *
  * @author Jens Halm
  */
class NCXRenderer {


  /** Inserts the specified (pre-rendered) navPoints into the NCX document template
    * and returns the content of the entire NCX file.
    */
  def fileContent (identifier: String, title: String, navPoints: String, depth: Int): String =
    s"""
      |
      |  
      |    
      |    
      |    
      |    
      |  
      |  
      |    $title
      |  
      |  
      |$navPoints
      |  
      |
    """.stripMargin


  /** Renders a single navPoint node.
    */
  private def navPoint (title: String, link: String, pos: Int, children: String): String =
    s"""    
       |      
       |        ${TagFormatter.escape(title)}
       |      
       |      
       |$children
       |    """.stripMargin

  /** Generates navPoints for the structure of the DocumentTree. 
    * Individual navPoints 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 structure to generate navPoints for
    * @return the navPoint XML nodes for the specified document tree
    */
  private def navPoints (bookNav: Seq[NavigationItem], pos: Iterator[Int] = Iterator.from(0)): String = {

    def linkOfFirstChild(children: Seq[NavigationItem]): NavigationLink = 
      children.head.link.getOrElse(linkOfFirstChild(children.head.content))

    bookNav.map { item =>
      navPoint(
        item.title.extractText,
        item.link.getOrElse(linkOfFirstChild(item.content)).target.render(),
        pos.next(), 
        navPoints(item.content, pos)
      ) // NCX does not allow navigation headers without links
    }.mkString("\n")
  }

  /** Renders the entire content of an NCX 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, identifier: String, depth: Option[Int]): String = {
    val bookNav = NavigationBuilder.forTree(result.tree, depth)
    val renderedNavPoints = navPoints(bookNav)
    def flattenItems (items: Seq[NavigationItem], level: Int): Int = 
      if (items.isEmpty) level else items.map(item => if (item.content.isEmpty) level else flattenItems(item.content, level + 1)).max
    fileContent(identifier, title, renderedNavPoints, flattenItems(bookNav, 1))
  }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy