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

scala.tools.nsc.doc.html.HtmlPage.scala Maven / Gradle / Ivy

The newest version!
/*
 * Scala (https://www.scala-lang.org)
 *
 * Copyright EPFL and Lightbend, Inc.
 *
 * Licensed under Apache License 2.0
 * (http://www.apache.org/licenses/LICENSE-2.0).
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package scala
package tools
package nsc
package doc
package html

import base._
import base.comment._
import model._
import scala.reflect.internal.Reporter
import scala.collection.{immutable, _}
import java.io.Writer
import java.net.URI

import javax.xml.stream.XMLOutputFactory

/** An html page that is part of a Scaladoc site.
  * @author David Bernard
  * @author Gilles Dubochet */
abstract class HtmlPage extends Page { thisPage =>
  import HtmlTags._

  /** The title of this page. */
  protected def title: String

  /** ScalaDoc reporter for error handling */
  protected def docletReporter: Reporter

  /** The page description */
  protected def description: String =
    // unless overwritten, will display the title in a spaced format, keeping - and .
    title.replaceAll("[^a-zA-Z0-9\\.\\-]+", " ").replaceAll("\\-+", " - ").replaceAll(" +", " ")

  /** The page keywords */
  protected def keywords: String =
    // unless overwritten, same as description, minus the " - "
    description.replaceAll(" - ", " ")

  /** Additional header elements (links, scripts, meta tags, etc.) required for this page. */
  protected def headers: Elems

  /** The body of this page. */
  def body: Elems

  def writeHtml(encoding: String)(w: Writer) = {
    val html =
      Html(Head(Meta(`http-equiv` = "X-UA-Compatible", content = "IE=edge") ::
                Meta(name = "viewport", content = "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no") ::
                HtmlTags.Title(elems= Txt(title)) ::
                Meta(name = "description", content = description) ::
                Meta(name = "keywords", content = keywords) ::
                Meta(`http-equiv` = "content-type", content = s"text/html; charset=${encoding}") :: headers) :: body)

    val xsw = XMLOutputFactory.newInstance.createXMLStreamWriter(w)
    xsw.writeDTD("")
    html.toXhtml(xsw, w)
    xsw.flush()
    xsw.close()
    w.write('\n')
  }

  def writeFor(site: HtmlFactory): Unit = {
    writeFile(site)(writeHtml(site.encoding))

    if (site.universe.settings.docRawOutput)
      writeFile(site, ".raw") {
        // we're only interested in the body, as this will go into the diff
        _.write(textOf(body))
      }
  }

  /** Transforms an optional comment into an styled HTML tree representing its body if it is defined, or into an empty
    * node sequence if it is not. */
  def commentToHtml(comment: Option[Comment]): Elems =
    (comment map (commentToHtml(_))) getOrElse NoElems

  /** Transforms a comment into an styled HTML tree representing its body. */
  def commentToHtml(comment: Comment): Elems =
    bodyToHtml(comment.body)

  def bodyToHtml(body: comment.Body): Elems =
    body.blocks.toList flatMap (blockToHtml(_))

  def blockToHtml(block: Block): Elems = (block match {
    case comment.Title(in, 1)          => H(3, inlineToHtml(in))
    case comment.Title(in, 2)          => H(4, inlineToHtml(in))
    case comment.Title(in, 3)          => H(5, inlineToHtml(in))
    case comment.Title(in, _)          => H(6, inlineToHtml(in))
    case Paragraph(in)                 => P(inlineToHtml(in))
    case comment.Code(data)            => Pre(SyntaxHigh(data)) //
{ Txt(data) }
case UnorderedList(items) => Ul(listItemsToHtml(items)) case OrderedList(items, listStyle) => Ol(`class`= listStyle, elems= listItemsToHtml(items)) case DefinitionList(items) => Dl(items.toList flatMap { case (t, d) => Dt(inlineToHtml(t)) :: Dd(blockToHtml(d)) :: NoElems }) case HorizontalRule() => Hr case tbl: comment.Table => tableToHtml(tbl) }) :: NoElems def listItemsToHtml(items: Seq[Block]) = items.foldLeft(NoElems){ (xmlList, item) => item match { // html requires sub ULs to be put into the last LI case OrderedList(_, _) | UnorderedList(_) => xmlList.init ++ Li(xmlList.last.elems ++ blockToHtml(item)) case Paragraph(inline) => xmlList :+ Li(inlineToHtml(inline)) // LIs are blocks, no need to use Ps case block => xmlList :+ Li(blockToHtml(block)) } } def inlineToHtml(inl: Inline): Elems = inl match { case Chain(items) => items.toList flatMap (inlineToHtml(_)) case Italic(in) => I(inlineToHtml(in)) :: NoElems case Bold(in) => B(inlineToHtml(in)) :: NoElems case Underline(in) => U(inlineToHtml(in)) :: NoElems case Superscript(in) => Sup(inlineToHtml(in)) :: NoElems case Subscript(in) => Sub(inlineToHtml(in)) :: NoElems case comment.Link(raw, title) => A(href = raw, target = "_blank", elems = inlineToHtml(title)) :: NoElems case Monospace(in) => Code(inlineToHtml(in)) :: NoElems case Text(text) => Txt(text) :: NoElems case Summary(in) => inlineToHtml(in) case HtmlTag(tag) => Raw(tag) :: NoElems case EntityLink(target, link) => linkToHtml(target, link, hasLinks = true) } def linkToHtml(text: Inline, link: LinkTo, hasLinks: Boolean): Elems = link match { case LinkToTpl(dtpl: TemplateEntity) => (if (hasLinks) A(href=relativeLinkTo(dtpl), `class` = "extype", id=dtpl.qualifiedName, name=dtpl.qualifiedName, elems=inlineToHtml(text)) else Span(`class` = "extype", name=dtpl.qualifiedName, elems=inlineToHtml(text))) :: NoElems case LinkToMember(mbr: MemberEntity, inTpl: TemplateEntity) => (if (hasLinks) A(href=relativeLinkTo(inTpl) + "#" + mbr.signature, `class`= "extmbr", id=mbr.qualifiedName, name=mbr.qualifiedName, elems=inlineToHtml(text)) else Span(`class`= "extmbr", name=mbr.qualifiedName, elems=inlineToHtml(text))) :: NoElems case Tooltip(tooltip) => Span(`class` = "extype", name=tooltip, elems = inlineToHtml(text)) :: NoElems case LinkToExternalTpl(name, baseUrlString, dtpl: TemplateEntity) => val baseUrl = new URI(Page.makeUrl(baseUrlString, Page.templateToPath(dtpl))) val url = if (name.isEmpty) baseUrl else new URI(baseUrl.getScheme, baseUrl.getSchemeSpecificPart, name) (if (hasLinks) A(href=url.toString, `class` = "extype", id=dtpl.qualifiedName, name=dtpl.qualifiedName, elems = inlineToHtml(text) ) else Span(`class` = "extype", name=dtpl.qualifiedName, elems= inlineToHtml(text))) :: NoElems case _ => inlineToHtml(text) } private def tableToHtml(table: comment.Table): Elem = { val comment.Table(header, columnOptions, rows) = table val colClass = Map( ColumnOption.ColumnOptionLeft -> "doctbl-left", ColumnOption.ColumnOptionCenter -> "doctbl-center", ColumnOption.ColumnOptionRight -> "doctbl-right" ) val cc = columnOptions.map(colClass) Table( thead = THead( Tr( (header.cells zip cc).toList.map{ case (cell, cls) => Th(cell.blocks.flatMap(blockToHtml).toList, `class` = cls)} ) :: immutable.Nil ), tbody = if (rows.nonEmpty) { TBody( rows.toList.map { row => Tr((row.cells zip cc).toList.map{ case (cell, cls) => Td(elems = cell.blocks.flatMap(blockToHtml).toList, `class`=cls) }) } ) } else null, `class` = "doctbl") } def typeToHtml(tpes: List[model.TypeEntity], hasLinks: Boolean): Elems = tpes match { case Nil => NoElems case List(tpe) => typeToHtml(tpe, hasLinks) case tpe :: rest => typeToHtml(tpe, hasLinks) ++ (Txt(" with ") :: typeToHtml(rest, hasLinks)) } def typeToHtml(tpe: model.TypeEntity, hasLinks: Boolean): Elems = { val string = tpe.name def toLinksOut(inPos: Int, starts: List[Int]): Elems = { if (starts.isEmpty && (inPos == string.length)) NoElems else if (starts.isEmpty) Txt(string.slice(inPos, string.length)) :: NoElems else if (inPos == starts.head) toLinksIn(inPos, starts) else { Txt(string.slice(inPos, starts.head)) :: toLinksIn(starts.head, starts) } } def toLinksIn(inPos: Int, starts: List[Int]): Elems = { val (link, width) = tpe.refEntity(inPos) val text = comment.Text(string.slice(inPos, inPos + width)) linkToHtml(text, link, hasLinks) ++ toLinksOut(inPos + width, starts.tail) } if (hasLinks) toLinksOut(0, tpe.refEntity.keySet.toList) else Txt(string) :: NoElems } def typesToHtml(tpess: List[model.TypeEntity], hasLinks: Boolean, sep: Elems): Elems = tpess match { case Nil => NoElems case tpe :: Nil => typeToHtml(tpe, hasLinks) case tpe :: tpes => typeToHtml(tpe, hasLinks) ++ sep ++ typesToHtml(tpes, hasLinks, sep) } def hasPage(e: DocTemplateEntity) = { e.isPackage || e.isTrait || e.isClass || e.isObject || e.isCase } /** Returns the HTML code that represents the template in `tpl` as a hyperlinked name. */ def templateToHtml(tpl: TemplateEntity, name: String = null): Elem = { val txt = Txt(if (name eq null) tpl.name else name) tpl match { case dTpl: DocTemplateEntity if hasPage(dTpl) => A(href= relativeLinkTo(dTpl), id= dTpl.qualifiedName, name= dTpl.qualifiedName, `class` = "extype", elems = txt :: NoElems) case _ => txt } } /** Returns the HTML code that represents the templates in `tpls` as a list of hyperlinked names. */ def templatesToHtml(tplss: List[TemplateEntity], sep: Elems): Elems = tplss match { case Nil => NoElems case tpl :: Nil => templateToHtml(tpl) :: NoElems case tpl :: tpls => templateToHtml(tpl) :: sep ++ templatesToHtml(tpls, sep) } object Image extends Enumeration { val Trait, Class, Type, Object, Package = Value } def permalink(template: Entity, isSelf: Boolean = true): Elem = Span(`class`= "permalink", elems= A(href=memberToUrl(template), title="Permalink", elems = I(`class`="material-icons", elems=Txt("\uE157")) )) def docEntityImageClass(tpl: DocTemplateEntity): String = tpl.kind + tpl.companion.fold("")("-companion-" + _.kind) def docEntityKindToCompanionTitle(ety: DocTemplateEntity, baseString: String = "See companion") = ety.companion match{ case Some(companion) => s"$baseString${ if(companion.isObject) " object" else if(companion.isTrait) " trait" else if(companion.isClass) " class" else "" }" case None => baseString } def companionAndPackage(tpl: DocTemplateEntity): Elems = Span(`class`= "morelinks", elems = tpl.companion match { case Some(companionTpl) => val objClassTrait = if (companionTpl.isObject) s"object ${tpl.name}" else if (companionTpl.isTrait) s"trait ${companionTpl.name}" else s"class ${companionTpl.name}" Div(elems = Txt("Companion ") :: A(href= relativeLinkTo(companionTpl), title= docEntityKindToCompanionTitle(tpl), elems=Txt(objClassTrait)) :: NoElems) case None => NoElems }) private def memberToUrl(template: Entity): String = { val (signature: Option[String], containingTemplate: TemplateEntity) = template match { case dte: DocTemplateEntity => (None, dte) case me: MemberEntity => (Some(me.signature), me.inTemplate) case tpl => (None, tpl) } val templatePath = templateToPath(containingTemplate) val url = "../" * (thisPage.path.size - 1) + templatePath.reverse.mkString("/") url + signature.map("#" + _).getOrElse("") } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy