
laika.bundle.RenderTheme.scala Maven / Gradle / Ivy
/*
* Copyright 2013-2018 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.bundle
import laika.ast._
import laika.collection.TransitionalCollectionOps._
import laika.config.OperationConfig
import laika.io.{InputTree, InputTreeOps}
/** Collects templates, styles and custom render functions to form
* a theme for a specific output format.
*
* @author Jens Halm
*/
trait RenderTheme {
/** The type of the Writer API a custom render function
* for this theme uses.
*/
type Writer
/** Specifies a custom render function that overrides one or more of the default
* renderers for the output format this instance uses.
*
* This method expects a function that returns a partial function as the result.
* The outer function allows to capture the writer instance to write to and will
* only be invoked once. The partial function will then be invoked for each
* element it is defined at.
*/
def customRenderer: Writer => RenderFunction
/** The default template to embed the nodes of the parsed markup documents in,
* in case no user-defined template overwrites the default.
*/
def defaultTemplate: Option[TemplateRoot]
/** The default styles to apply in addition to any user-defined styles.
*
* These styles are only processed for output formats where the transformer
* processes the CSS to adjust the rendered output. This is only the case
* for PDF and XSL-FO.
*
* Styling for other formats like HTML has to happen via static files
* in the input directory that are merely copied over to the target directory
* by the transformer.
*/
def defaultStyles: StyleDeclarationSet
/** Specifies any additional static documents to be copied over to the
* target directory in each transform operation.
*
* This is allows for a central collection of CSS, JavaScript, image and
* other files needed for a specific theme.
*/
def staticDocuments: StaticDocuments
/** Returns the default template specified by this theme or the
* system-wide default in case the default is empty.
*/
def defaultTemplateOrFallback: TemplateRoot = defaultTemplate.getOrElse(TemplateRoot.fallback)
}
/** A collection of static documents to be copied over to the
* target directory in each transform operation.
*
* This is allows for a central collection of CSS, JavaScript, image and
* other files needed for a specific theme.
*/
case class StaticDocuments (tree: DocumentTree) {
/** Merges this instance with the specified base recursively.
*/
def merge (base: DocumentTree): DocumentTree = {
def mergeContent (content: Seq[TreeContent]): Seq[TreeContent] = {
val trees = content.collect{ case t: DocumentTree => t }.groupBy(_.path).mapValuesStrict(_.reduceLeft(mergeTrees)).values.toList
(content.filter(_.isInstanceOf[Document]) ++ trees).sortBy(_.position)
}
def mergeTrees (left: DocumentTree, right: DocumentTree): DocumentTree = {
right.copy(
content = mergeContent(left.content ++ right.content),
additionalContent = left.additionalContent ++ right.additionalContent
)
}
mergeTrees(tree, base)
}
}
/** API for defining a collection of static documents
* based on one or more directories.
*
* Like with all Laika IO, these may be actual file system directories
* or virtual in-memory trees of input documents.
*/
object StaticDocuments extends InputTreeOps {
val empty = StaticDocuments(DocumentTree(Path.Root, Nil))
override type InputTreeResult = StaticDocuments
override def config: OperationConfig = OperationConfig(Seq(new ExtensionBundle {
override def docTypeMatcher: PartialFunction[Path, DocumentType] = { case _ => DocumentType.Static }
}))
override def fromInputTree (inputTree: InputTree): StaticDocuments = {
def collectDocuments (currentTree: InputTree): DocumentTree = {
val trees = currentTree.subtrees map collectDocuments
val static = currentTree.staticDocuments map StaticDocument
DocumentTree(currentTree.path, trees, additionalContent = static, sourcePaths = currentTree.sourcePaths)
}
StaticDocuments(collectDocuments(inputTree))
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy