summaryrefslogtreecommitdiff
path: root/src/scaladoc
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-01-08 23:20:04 +0100
committerFelix Mulder <felix.mulder@gmail.com>2016-02-17 08:25:29 +0100
commit7b07a78cc0831a08f2d39a259dec2454c7d4cc1e (patch)
treeb90dd022688b5fec4a0a39fce2e4db9fb1aed5a7 /src/scaladoc
parentc524f18ee4959f6fe8297971fc882e63468c4317 (diff)
downloadscala-7b07a78cc0831a08f2d39a259dec2454c7d4cc1e.tar.gz
scala-7b07a78cc0831a08f2d39a259dec2454c7d4cc1e.tar.bz2
scala-7b07a78cc0831a08f2d39a259dec2454c7d4cc1e.zip
Scaladoc: Add new search, featuring entity and member search
This commit adds a revamped search function for the scaladoc tool. It also contains a number of small fixes for HTML-layout and JavaScript issues. The search is implemented by enhancing the scheduler and using JavaScript promises. List of changes/additions: * Revamped search functionality - Search members as well as entities - Preserve keyboard navigation - Scroll to selected entity if outside of viewport - Non-blocking, cancelable * Display of library name (top left) * Refactored scheduler * Cleanup of HTML layout - Remove left pane - Better mobile layout, no need for dynamic offsets - Remove unused element classes - Remove iframe structure - Better layout for kinds
Diffstat (limited to 'src/scaladoc')
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/doclet/Indexer.scala2
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala5
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala17
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala17
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/Page.scala2
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/page/DeprecatedIndex.scala4
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala1046
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/page/Index.scala129
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/page/IndexScript.scala88
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/page/ReferenceIndex.scala4
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala17
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css554
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js872
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.eotbin0 -> 30159 bytes
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.ttfbin0 -> 76144 bytes
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.woffbin0 -> 33288 bytes
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/scheduler.js56
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css213
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js97
19 files changed, 2183 insertions, 940 deletions
diff --git a/src/scaladoc/scala/tools/nsc/doc/doclet/Indexer.scala b/src/scaladoc/scala/tools/nsc/doc/doclet/Indexer.scala
index 0cdd47182f..12fee69cca 100644
--- a/src/scaladoc/scala/tools/nsc/doc/doclet/Indexer.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/doclet/Indexer.scala
@@ -18,4 +18,4 @@ trait Indexer extends Generator with Universer {
indexField != null
}
-} \ No newline at end of file
+}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala b/src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala
index 21c5f6bb67..cad7cf3298 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/Doclet.scala
@@ -3,7 +3,8 @@
* @author David Bernard, Manohar Jonnalagedda
*/
-package scala.tools.nsc.doc
+package scala.tools.nsc
+package doc
package html
import doclet._
@@ -13,7 +14,7 @@ import doclet._
class Doclet extends Generator with Universer with Indexer {
def generateImpl() {
- new html.HtmlFactory(universe, index).generate()
+ new html.HtmlFactory(universe, index, new ScalaDocReporter(universe.settings)).generate()
}
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala
index 6076b1708c..65c540d4c5 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala
@@ -16,7 +16,8 @@ import page.diagram._
/** A class that can generate Scaladoc sites to some fixed root folder.
* @author David Bernard
* @author Gilles Dubochet */
-class HtmlFactory(val universe: doc.Universe, index: doc.Index) {
+class HtmlFactory(val universe: doc.Universe, index: doc.Index, val reporter: ScalaDocReporter) {
+ import page.{IndexScript, EntityPage}
/** The character encoding to be used for generated Scaladoc sites.
* This value is currently always UTF-8. */
@@ -34,6 +35,9 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) {
"trait_comp.svg",
"permalink.svg",
"abstract_type.svg",
+ "lato-v11-latin-100.eot",
+ "lato-v11-latin-100.ttf",
+ "lato-v11-latin-100.woff",
"lato-v11-latin-regular.eot",
"lato-v11-latin-regular.ttf",
"lato-v11-latin-regular.woff",
@@ -96,14 +100,15 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) {
libResources foreach (s => copyResource("lib/" + s))
- new page.Index(universe, index) writeFor this
- new page.IndexScript(universe, index) writeFor this
+ IndexScript(universe, index) writeFor this
+
if (index.hasDeprecatedMembers)
- new page.DeprecatedIndex(universe, index) writeFor this
+ new page.DeprecatedIndex(universe, index, reporter) writeFor this
try {
writeTemplates(_ writeFor this)
+
for (letter <- index.firstLetterIndex) {
- new html.page.ReferenceIndex(letter._1, index, universe) writeFor this
+ new html.page.ReferenceIndex(letter._1, index, universe, reporter) writeFor this
}
} finally {
DiagramStats.printStats(universe.settings)
@@ -117,7 +122,7 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) {
def writeTemplate(tpl: DocTemplateEntity) {
if (!(written contains tpl)) {
val diagramGenerator: DiagramGenerator = new DotDiagramGenerator(universe.settings, universe.dotRunner)
- writeForThis(new page.Template(universe, diagramGenerator, tpl))
+ writeForThis(page.EntityPage(universe, diagramGenerator, tpl, reporter))
written += tpl
tpl.templates collect { case d: DocTemplateEntity => d } map writeTemplate
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala
index 16a2fc59d4..0eb90d8942 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala
@@ -26,6 +26,9 @@ abstract class HtmlPage extends Page { thisPage =>
/** The title of this page. */
protected def title: String
+ /** ScalaDoc reporter for error handling */
+ protected def reporter: ScalaDocReporter
+
/** The page description */
protected def description: String =
// unless overwritten, will display the title in a spaced format, keeping - and .
@@ -48,7 +51,7 @@ abstract class HtmlPage extends Page { thisPage =>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
- <meta name="viewport" content="width=device-width, initial-scale=1"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>{ title }</title>
<meta name="description" content={ description }/>
<meta name="keywords" content={ keywords }/>
@@ -281,7 +284,7 @@ abstract class HtmlPage extends Page { thisPage =>
}
}</span>
- def memberToUrl(template: Entity, isSelf: Boolean = true): String = {
+ private def memberToUrl(template: Entity, isSelf: Boolean = true): String = {
val (signature: Option[String], containingTemplate: TemplateEntity) = template match {
case dte: DocTemplateEntity if (!isSelf) => (Some(dte.signature), dte.inTemplate)
case dte: DocTemplateEntity => (None, dte)
@@ -289,12 +292,8 @@ abstract class HtmlPage extends Page { thisPage =>
case tpl => (None, tpl)
}
- def hashFromPath(templatePath: List[String]): String =
- ((templatePath.head.replace(".html", "") :: templatePath.tail).reverse).mkString(".")
-
- val containingTemplatePath = templateToPath(containingTemplate)
- val url = "../" * (containingTemplatePath.size - 1) + "index.html"
- val hash = hashFromPath(containingTemplatePath)
- s"$url#$hash" + signature.map("@" + _).getOrElse("")
+ val templatePath = templateToPath(containingTemplate)
+ val url = "../" * (templatePath.size - 1) + templatePath.reverse.mkString("/")
+ url + signature.map("#" + _).getOrElse("")
}
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/Page.scala b/src/scaladoc/scala/tools/nsc/doc/html/Page.scala
index 93950fd0a7..aeda84adaf 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/Page.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/Page.scala
@@ -78,7 +78,7 @@ abstract class Page {
}
val (file, pack) =
tpl match {
- case p: Package => ("package.html", p)
+ case p: Package => ("index.html", p)
case _ => downInner(doName(tpl), tpl)
}
file :: downPacks(pack)
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/DeprecatedIndex.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/DeprecatedIndex.scala
index f257153bd7..e8cb58c732 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/page/DeprecatedIndex.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/page/DeprecatedIndex.scala
@@ -11,7 +11,9 @@ package page
import doc.model._
-class DeprecatedIndex(universe: Universe, index: doc.Index) extends HtmlPage {
+class DeprecatedIndex(universe: Universe, index: doc.Index, rep: ScalaDocReporter) extends HtmlPage {
+
+ def reporter = rep
def path = List("deprecated-list.html")
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala
new file mode 100644
index 0000000000..503d54185a
--- /dev/null
+++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Entity.scala
@@ -0,0 +1,1046 @@
+/* NSC -- new Scala compiler
+ * Copyright 2007-2016 LAMP/EPFL
+ * @author David Bernard, Manohar Jonnalagedda, Felix Mulder
+ */
+
+package scala
+package tools
+package nsc
+package doc
+package html
+package page
+
+import base._
+import base.comment._
+
+import scala.collection.mutable
+import scala.xml.{NodeSeq, Text, UnprefixedAttribute}
+import scala.language.postfixOps
+
+import model._
+import model.diagram._
+import diagram._
+
+trait EntityPage extends HtmlPage {
+ def universe: doc.Universe
+ def generator: DiagramGenerator
+ def tpl: DocTemplateEntity
+ def reporter: ScalaDocReporter
+
+ override val path = templateToPath(tpl)
+
+ def title = {
+ val s = universe.settings
+ ( if (!s.doctitle.isDefault) s.doctitle.value + " " else "" ) +
+ ( if (!s.docversion.isDefault) s.docversion.value else "" ) +
+ ( if ((!s.doctitle.isDefault || !s.docversion.isDefault) && tpl.qualifiedName != "_root_") " - " + tpl.qualifiedName else "" )
+ }
+
+ def headers =
+ <xml:group>
+ <link href={ relativeLinkTo{List("index.css", "lib")} } media="screen" type="text/css" rel="stylesheet"/>
+ <link href={ relativeLinkTo{List("template.css", "lib")} } media="screen" type="text/css" rel="stylesheet"/>
+ <link href={ relativeLinkTo{List("diagrams.css", "lib")} } media="screen" type="text/css" rel="stylesheet" id="diagrams-css" />
+ <script type="text/javascript" src={ relativeLinkTo{List("jquery.js", "lib")} }></script>
+ <script type="text/javascript" src={ relativeLinkTo{List("jquery.panzoom.min.js", "lib")} }></script>
+ <script type="text/javascript" src={ relativeLinkTo{List("jquery.mousewheel.min.js", "lib")} }></script>
+ <script type="text/javascript" src={ relativeLinkTo{List("index.js", "lib")} }></script>
+ <script type="text/javascript" src={ relativeLinkTo{List("index.js")} }></script>
+ <script type="text/javascript" src={ relativeLinkTo{List("scheduler.js", "lib")} }></script>
+ <script type="text/javascript" src={ relativeLinkTo{List("template.js", "lib")} }></script>
+ <script type="text/javascript" src={ relativeLinkTo{List("tools.tooltip.js", "lib")} }></script>
+ { if (universe.settings.docDiagrams.value) {
+ <script type="text/javascript" src={ relativeLinkTo{List("modernizr.custom.js", "lib")} }></script>
+ <script type="text/javascript" src={ relativeLinkTo{List("diagrams.js", "lib")} } id="diagrams-js"></script>
+ } else NodeSeq.Empty }
+ <script type="text/javascript">
+ /* this variable can be used by the JS to determine the path to the root document */
+ var toRoot = '{ val p = templateToPath(tpl); "../" * (p.size - 1) }';
+ </script>
+ </xml:group>
+
+ def body =
+ <body>
+ { search }
+ <div id="search-results">
+ <div id="results-content">
+ <div id="entity-results"></div>
+ <div id="member-results"></div>
+ </div>
+ </div>
+ <div id="content-container" style="-webkit-overflow-scrolling: touch;">
+ <div id="content">
+ { content }
+ </div>
+ </div>
+ </body>
+
+ def search =
+ <div id="search">
+ <span id="doc-title">
+ {universe.settings.doctitle.value}
+ <span id="doc-version">
+ {
+ val version = universe.settings.docversion.value
+
+ if (version.length > "XX.XX.XX-XXX".length) {
+ reporter.warning(null,
+ s"doc-version ($version) is too long to be displayed in the webview")
+ ""
+ } else version
+ }
+ </span>
+ </span>
+ <span class="close-results"><span class="left">&lt;</span> Back</span>
+ <div id="textfilter">
+ <span class="input">
+ <input autocapitalize="none" placeholder="Search" id="index-input" type="text" accesskey="/"/>
+ <i class="clear material-icons">&#xE14C;</i>
+ <i id="search-icon" class="material-icons">&#xE8B6;</i>
+ </span>
+ </div>
+ </div>
+
+ val valueMembers =
+ tpl.methods ++ tpl.values ++ tpl.templates.filter(x => x.isObject || x.isPackage) sorted
+
+ val (absValueMembers, nonAbsValueMembers) =
+ valueMembers partition (_.isAbstract)
+
+ val (deprValueMembers, nonDeprValueMembers) =
+ nonAbsValueMembers partition (_.deprecation.isDefined)
+
+ val (concValueMembers, shadowedImplicitMembers) =
+ nonDeprValueMembers partition (!_.isShadowedOrAmbiguousImplicit)
+
+ val typeMembers =
+ tpl.abstractTypes ++ tpl.aliasTypes ++ tpl.templates.filter(x => x.isTrait || x.isClass) sorted (implicitly[Ordering[MemberEntity]])
+
+ val constructors = (tpl match {
+ case cls: Class => (cls.constructors: List[MemberEntity]).sorted
+ case _ => Nil
+ })
+
+ /* for body, there is a special case for AnyRef, otherwise AnyRef appears
+ * like a package/object this problem should be fixed, this implementation
+ * is just a patch. */
+ val content = {
+ val templateName = if (tpl.isRootPackage) "root package" else tpl.name
+ val displayName = tpl.companion match {
+ case Some(companion) if (companion.visibility.isPublic && companion.inSource != None) =>
+ <a href={relativeLinkTo(companion)} title={docEntityKindToCompanionTitle(tpl)}>{ templateName }</a>
+ case _ =>
+ templateName
+ }
+ val owner = {
+ if (tpl.isRootPackage || tpl.inTemplate.isRootPackage)
+ NodeSeq.Empty
+ else
+ <p id="owner">{ templatesToHtml(tpl.inTemplate.toRoot.reverse.tail, scala.xml.Text(".")) }</p>
+ }
+
+ <body class={ tpl.kind + (if (tpl.isType) " type" else " value") }>
+ <div id="definition">
+ {
+ val (src, alt) = docEntityKindToBigImage(tpl)
+
+ val identifier = alt.toString.substring(0,2).toLowerCase
+
+ tpl.companion match {
+ case Some(companion) if (companion.visibility.isPublic && companion.inSource != None) =>
+ <a href={relativeLinkTo(companion)} title={docEntityKindToCompanionTitle(tpl)}><div class={s"big-circle companion $identifier"}>{ identifier.substring(0,1) }</div></a>
+ case _ =>
+ <div class={ "big-circle " + alt.toString.toLowerCase }>{ identifier.substring(0,1) }</div>
+ }}
+ { owner }
+ <h1>{ displayName }</h1>{
+ if (tpl.isPackage) NodeSeq.Empty else <h3>{companionAndPackage(tpl)}</h3>
+ }{ permalink(tpl) }
+ { signature(tpl, isSelf = true) }
+ </div>
+
+ { memberToCommentHtml(tpl, tpl.inTemplate, isSelf = true) }
+
+ <div id="mbrsel">
+ <div class='toggle'></div>
+ <div id='memberfilter'><span class='input'><input id='mbrsel-input' placeholder='Filter members' type='text' accesskey='/'/></span><span class='clear'>✖</span></div>
+ <div id='filterby'>
+ { if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty && (!universe.settings.docGroups.value || (tpl.members.map(_.group).distinct.length == 1)))
+ NodeSeq.Empty
+ else
+ <div id="order">
+ <span class="filtertype">Ordering</span>
+ <ol>
+ {
+ if (!universe.settings.docGroups.value || (tpl.members.map(_.group).distinct.length == 1))
+ NodeSeq.Empty
+ else
+ <li class="group out"><span>Grouped</span></li>
+ }
+ <li class="alpha in"><span>Alphabetic</span></li>
+ {
+ if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty)
+ NodeSeq.Empty
+ else
+ <li class="inherit out"><span>By Inheritance</span></li>
+ }
+ </ol>
+ </div>
+ }
+ { if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty) NodeSeq.Empty else
+ {
+ if (!tpl.linearizationTemplates.isEmpty)
+ <div class="ancestors">
+ <span class="filtertype">Inherited<br/>
+ </span>
+ <ol id="linearization">
+ { (tpl :: tpl.linearizationTemplates).map(wte => <li class="in" name={ wte.qualifiedName }><span>{ wte.name }</span></li>) }
+ </ol>
+ </div>
+ else NodeSeq.Empty
+ } ++ {
+ if (!tpl.conversions.isEmpty)
+ <div class="ancestors">
+ <span class="filtertype">Implicitly<br/>
+ </span>
+ <ol id="implicits"> {
+ tpl.conversions.map { conv =>
+ val name = conv.conversionQualifiedName
+ val hide = universe.settings.hiddenImplicits(name)
+ <li class="in" name={ name } data-hidden={ hide.toString }><span>{ "by " + conv.conversionShortName }</span></li>
+ }
+ }
+ </ol>
+ </div>
+ else NodeSeq.Empty
+ } ++
+ <div class="ancestors">
+ <span class="filtertype"></span>
+ <ol>
+ <li class="hideall out"><span>Hide All</span></li>
+ <li class="showall in"><span>Show All</span></li>
+ </ol>
+ </div>
+ }
+ {
+ <div id="visbl">
+ <span class="filtertype">Visibility</span>
+ <ol><li class="public in"><span>Public</span></li><li class="all out"><span>All</span></li></ol>
+ </div>
+ }
+ </div>
+ </div>
+
+ <div id="template">
+ <div id="allMembers">
+ { if (constructors.isEmpty) NodeSeq.Empty else
+ <div id="constructors" class="members">
+ <h3>Instance Constructors</h3>
+ <ol>{ constructors map (memberToHtml(_, tpl)) }</ol>
+ </div>
+ }
+
+ { if (typeMembers.isEmpty) NodeSeq.Empty else
+ <div id="types" class="types members">
+ <h3>Type Members</h3>
+ <ol>{ typeMembers map (memberToHtml(_, tpl)) }</ol>
+ </div>
+ }
+
+ { if (absValueMembers.isEmpty) NodeSeq.Empty else
+ <div class="values members">
+ <h3>Abstract Value Members</h3>
+ <ol>{ absValueMembers map (memberToHtml(_, tpl)) }</ol>
+ </div>
+ }
+
+ { if (concValueMembers.isEmpty) NodeSeq.Empty else
+ <div class="values members">
+ <h3>{ if (absValueMembers.isEmpty) "Value Members" else "Concrete Value Members" }</h3>
+ <ol>{ concValueMembers map (memberToHtml(_, tpl)) }</ol>
+ </div>
+ }
+
+ { if (shadowedImplicitMembers.isEmpty) NodeSeq.Empty else
+ <div class="values members">
+ <h3>Shadowed Implicit Value Members</h3>
+ <ol>{ shadowedImplicitMembers map (memberToHtml(_, tpl)) }</ol>
+ </div>
+ }
+
+ { if (deprValueMembers.isEmpty) NodeSeq.Empty else
+ <div class="values members">
+ <h3>Deprecated Value Members</h3>
+ <ol>{ deprValueMembers map (memberToHtml(_, tpl)) }</ol>
+ </div>
+ }
+ </div>
+
+ <div id="inheritedMembers">
+ {
+ // linearization
+ NodeSeq fromSeq (for ((superTpl, superType) <- (tpl.linearizationTemplates zip tpl.linearizationTypes)) yield
+ <div class="parent" name={ superTpl.qualifiedName }>
+ <h3>Inherited from {
+ typeToHtmlWithStupidTypes(tpl, superTpl, superType)
+ }</h3>
+ </div>
+ )
+ }
+ {
+ // implicitly inherited
+ NodeSeq fromSeq (for (conversion <- (tpl.conversions)) yield
+ <div class="conversion" name={ conversion.conversionQualifiedName }>
+ <h3>Inherited by implicit conversion { conversion.conversionShortName } from
+ { typeToHtml(tpl.resultType, hasLinks = true) } to { typeToHtml(conversion.targetType, hasLinks = true) }
+ </h3>
+ </div>
+ )
+ }
+ </div>
+
+ <div id="groupedMembers">
+ {
+ val allGroups = tpl.members.map(_.group).distinct
+ val orderedGroups = allGroups.map(group => (tpl.groupPriority(group), group)).sorted.map(_._2)
+ // linearization
+ NodeSeq fromSeq (for (group <- orderedGroups) yield
+ <div class="group" name={ group }>
+ <h3>{ tpl.groupName(group) }</h3>
+ {
+ tpl.groupDescription(group) match {
+ case Some(body) => <div class="comment cmt">{ bodyToHtml(body) }</div>
+ case _ => NodeSeq.Empty
+ }
+ }
+ </div>
+ )
+ }
+ </div>
+
+ </div>
+
+ <div id="tooltip" ></div>
+
+ {
+ if (Set("epfl", "EPFL").contains(tpl.universe.settings.docfooter.value))
+ <div id="footer">Scala programming documentation. Copyright (c) 2003-2016 <a href="http://www.epfl.ch" target="_top">EPFL</a>, with contributions from <a href="http://typesafe.com" target="_top">Typesafe</a>.</div>
+ else
+ <div id="footer"> { tpl.universe.settings.docfooter.value } </div>
+ }
+ </body>
+ }
+
+ def memberToHtml(mbr: MemberEntity, inTpl: DocTemplateEntity): NodeSeq = {
+ // Sometimes it's same, do we need signatureCompat still?
+ val sig = if (mbr.signature == mbr.signatureCompat) {
+ <a id={ mbr.signature }/>
+ } else {
+ <a id={ mbr.signature }/><a id={ mbr.signatureCompat }/>
+ }
+
+ val memberComment = memberToCommentHtml(mbr, inTpl, isSelf = false)
+ <li name={ mbr.definitionName } visbl={ if (mbr.visibility.isProtected) "prt" else "pub" }
+ data-isabs={ mbr.isAbstract.toString }
+ fullComment={ if(memberComment.filter(_.label=="div").isEmpty) "no" else "yes" }
+ group={ mbr.group }>
+ { sig }
+ { signature(mbr, isSelf = false) }
+ { memberComment }
+ </li>
+ }
+
+ def memberToCommentHtml(mbr: MemberEntity, inTpl: DocTemplateEntity, isSelf: Boolean): NodeSeq = {
+ mbr match {
+ case dte: DocTemplateEntity if isSelf =>
+ // comment of class itself
+ <xml:group>
+ <div id="comment" class="fullcommenttop">{ memberToCommentBodyHtml(mbr, inTpl, isSelf = true) }</div>
+ </xml:group>
+ case _ =>
+ // comment of non-class member or non-documentented inner class
+ val commentBody = memberToCommentBodyHtml(mbr, inTpl, isSelf = false)
+ if (commentBody.isEmpty)
+ NodeSeq.Empty
+ else {
+ val shortComment = memberToShortCommentHtml(mbr, isSelf)
+ val longComment = memberToUseCaseCommentHtml(mbr, isSelf) ++ memberToCommentBodyHtml(mbr, inTpl, isSelf)
+
+ val includedLongComment = if (shortComment.text.trim == longComment.text.trim)
+ NodeSeq.Empty
+ else
+ <div class="fullcomment">{ longComment }</div>
+
+ shortComment ++ includedLongComment
+ }
+ }
+ }
+
+ def memberToUseCaseCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq = {
+ mbr match {
+ case nte: NonTemplateMemberEntity if nte.isUseCase =>
+ inlineToHtml(comment.Text("[use case] "))
+ case _ => NodeSeq.Empty
+ }
+ }
+
+ def memberToShortCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq =
+ mbr.comment.fold(NodeSeq.Empty) { comment =>
+ <p class="shortcomment cmt">{ memberToUseCaseCommentHtml(mbr, isSelf) }{ inlineToHtml(comment.short) }</p>
+ }
+
+ def memberToInlineCommentHtml(mbr: MemberEntity, isSelf: Boolean): NodeSeq =
+ <p class="comment cmt">{ inlineToHtml(mbr.comment.get.short) }</p>
+
+ def memberToCommentBodyHtml(mbr: MemberEntity, inTpl: DocTemplateEntity, isSelf: Boolean, isReduced: Boolean = false): NodeSeq = {
+ val s = universe.settings
+
+ val memberComment =
+ if (mbr.comment.isEmpty) NodeSeq.Empty
+ else <div class="comment cmt">{ commentToHtml(mbr.comment) }</div>
+
+ val authorComment =
+ if (! s.docAuthor || mbr.comment.isEmpty ||
+ mbr.comment.isDefined && mbr.comment.get.authors.isEmpty) NodeSeq.Empty
+ else <div class="comment cmt">
+ {if (mbr.comment.get.authors.size > 1) <h6>Authors:</h6> else <h6>Author:</h6>}
+ { mbr.comment.get.authors map bodyToHtml}
+ </div>
+
+ val paramComments = {
+ val prs: List[ParameterEntity] = mbr match {
+ case cls: Class => cls.typeParams ::: cls.valueParams.flatten
+ case trt: Trait => trt.typeParams
+ case dfe: Def => dfe.typeParams ::: dfe.valueParams.flatten
+ case ctr: Constructor => ctr.valueParams.flatten
+ case _ => Nil
+ }
+
+ def paramCommentToHtml(prs: List[ParameterEntity], comment: Comment): NodeSeq = prs match {
+
+ case (tp: TypeParam) :: rest =>
+ val paramEntry: NodeSeq = {
+ <dt class="tparam">{ tp.name }</dt><dd class="cmt">{ bodyToHtml(comment.typeParams(tp.name)) }</dd>
+ }
+ paramEntry ++ paramCommentToHtml(rest, comment)
+
+ case (vp: ValueParam) :: rest =>
+ val paramEntry: NodeSeq = {
+ <dt class="param">{ vp.name }</dt><dd class="cmt">{ bodyToHtml(comment.valueParams(vp.name)) }</dd>
+ }
+ paramEntry ++ paramCommentToHtml(rest, comment)
+
+ case _ =>
+ NodeSeq.Empty
+ }
+
+ mbr.comment.fold(NodeSeq.Empty) { comment =>
+ val cmtedPrs = prs filter {
+ case tp: TypeParam => comment.typeParams isDefinedAt tp.name
+ case vp: ValueParam => comment.valueParams isDefinedAt vp.name
+ }
+ if (cmtedPrs.isEmpty && comment.result.isEmpty) NodeSeq.Empty
+ else {
+ <dl class="paramcmts block">{
+ paramCommentToHtml(cmtedPrs, comment) ++ (
+ comment.result match {
+ case None => NodeSeq.Empty
+ case Some(cmt) =>
+ <dt>returns</dt><dd class="cmt">{ bodyToHtml(cmt) }</dd>
+ })
+ }</dl>
+ }
+ }
+ }
+
+ val implicitInformation = mbr.byConversion match {
+ case Some(conv) =>
+ <dt class="implicit">Implicit</dt> ++
+ {
+ val targetType = typeToHtml(conv.targetType, hasLinks = true)
+ val conversionMethod = conv.convertorMethod match {
+ case Left(member) => Text(member.name)
+ case Right(name) => Text(name)
+ }
+
+ // strip off the package object endings, they make things harder to follow
+ val conversionOwnerQualifiedNane = conv.convertorOwner.qualifiedName.stripSuffix(".package")
+ val conversionOwner = templateToHtml(conv.convertorOwner, conversionOwnerQualifiedNane)
+
+ val constraintText = conv.constraints match {
+ case Nil =>
+ NodeSeq.Empty
+ case List(constraint) =>
+ scala.xml.Text("This conversion will take place only if ") ++ constraintToHtml(constraint) ++ scala.xml.Text(".")
+ case List(constraint1, constraint2) =>
+ scala.xml.Text("This conversion will take place only if ") ++ constraintToHtml(constraint1) ++
+ scala.xml.Text(" and at the same time ") ++ constraintToHtml(constraint2) ++ scala.xml.Text(".")
+ case constraints =>
+ <br/> ++ "This conversion will take place only if all of the following constraints are met:" ++ <br/> ++ {
+ var index = 0
+ constraints map { constraint => scala.xml.Text({ index += 1; index } + ". ") ++ constraintToHtml(constraint) ++ <br/> }
+ }
+ }
+
+ <dd>
+ This member is added by an implicit conversion from { typeToHtml(inTpl.resultType, hasLinks = true) } to
+ { targetType } performed by method { conversionMethod } in { conversionOwner }.
+ { constraintText }
+ </dd>
+ } ++ {
+ if (mbr.isShadowedOrAmbiguousImplicit) {
+ // These are the members that are shadowing or ambiguating the current implicit
+ // see ImplicitMemberShadowing trait for more information
+ val shadowingSuggestion = {
+ val params = mbr match {
+ case d: Def => d.valueParams map (_ map (_ name) mkString("(", ", ", ")")) mkString
+ case _ => "" // no parameters
+ }
+ <br/> ++ scala.xml.Text("To access this member you can use a ") ++
+ <a href="http://stackoverflow.com/questions/2087250/what-is-the-purpose-of-type-ascription-in-scala"
+ target="_blank">type ascription</a> ++ scala.xml.Text(":") ++
+ <br/> ++ <div class="cmt"><pre>{"(" + Template.lowerFirstLetter(tpl.name) + ": " + conv.targetType.name + ")." + mbr.name + params }</pre></div>
+ }
+
+ val shadowingWarning: NodeSeq =
+ if (mbr.isShadowedImplicit)
+ scala.xml.Text("This implicitly inherited member is shadowed by one or more members in this " +
+ "class.") ++ shadowingSuggestion
+ else if (mbr.isAmbiguousImplicit)
+ scala.xml.Text("This implicitly inherited member is ambiguous. One or more implicitly " +
+ "inherited members have similar signatures, so calling this member may produce an ambiguous " +
+ "implicit conversion compiler error.") ++ shadowingSuggestion
+ else NodeSeq.Empty
+
+ <dt class="implicit">Shadowing</dt> ++
+ <dd>{ shadowingWarning }</dd>
+
+ } else NodeSeq.Empty
+ }
+ case _ =>
+ NodeSeq.Empty
+ }
+
+ // --- start attributes block vals
+ val attributes: NodeSeq = {
+ val fvs: List[comment.Paragraph] = visibility(mbr).toList
+ if (fvs.isEmpty || isReduced) NodeSeq.Empty
+ else {
+ <dt>Attributes</dt>
+ <dd>{ fvs map { fv => { inlineToHtml(fv.text) ++ scala.xml.Text(" ") } } }</dd>
+ }
+ }
+
+ val definitionClasses: NodeSeq = {
+ val inDefTpls = mbr.inDefinitionTemplates
+ if ((inDefTpls.tail.isEmpty && (inDefTpls.head == inTpl)) || isReduced) NodeSeq.Empty
+ else {
+ <dt>Definition Classes</dt>
+ <dd>{ templatesToHtml(inDefTpls, scala.xml.Text(" → ")) }</dd>
+ }
+ }
+
+ val fullSignature: NodeSeq = {
+ mbr match {
+ case nte: NonTemplateMemberEntity if nte.isUseCase =>
+ <div class="full-signature-block toggleContainer">
+ <span class="toggle">Full Signature</span>
+ <div class="hiddenContent full-signature-usecase">{ signature(nte.useCaseOf.get,isSelf = true) }</div>
+ </div>
+ case _ => NodeSeq.Empty
+ }
+ }
+
+ val selfType: NodeSeq = mbr match {
+ case dtpl: DocTemplateEntity if (isSelf && !dtpl.selfType.isEmpty && !isReduced) =>
+ <dt>Self Type</dt>
+ <dd>{ typeToHtml(dtpl.selfType.get, hasLinks = true) }</dd>
+ case _ => NodeSeq.Empty
+ }
+
+ val annotations: NodeSeq = {
+ // A list of annotations which don't show their arguments, e. g. because they are shown separately.
+ val annotationsWithHiddenArguments = List("deprecated", "Deprecated", "migration")
+
+ def showArguments(annotation: Annotation) =
+ !(annotationsWithHiddenArguments.contains(annotation.qualifiedName))
+
+ if (!mbr.annotations.isEmpty) {
+ <dt>Annotations</dt>
+ <dd>{
+ mbr.annotations.map { annot =>
+ <xml:group>
+ <span class="name">@{ templateToHtml(annot.annotationClass) }</span>{
+ if (showArguments(annot)) argumentsToHtml(annot.arguments) else NodeSeq.Empty
+ }
+ </xml:group>
+ }
+ }
+ </dd>
+ } else NodeSeq.Empty
+ }
+
+ val sourceLink: NodeSeq = mbr match {
+ case dtpl: DocTemplateEntity if (isSelf && dtpl.sourceUrl.isDefined && dtpl.inSource.isDefined && !isReduced) =>
+ val (absFile, _) = dtpl.inSource.get
+ <dt>Source</dt>
+ <dd>{ <a href={ dtpl.sourceUrl.get.toString } target="_blank">{ Text(absFile.file.getName) }</a> }</dd>
+ case _ => NodeSeq.Empty
+ }
+
+ val deprecation: NodeSeq =
+ mbr.deprecation match {
+ case Some(deprecation) if !isReduced =>
+ <dt>Deprecated</dt>
+ <dd class="cmt">{ bodyToHtml(deprecation) }</dd>
+ case _ => NodeSeq.Empty
+ }
+
+ val migration: NodeSeq =
+ mbr.migration match {
+ case Some(migration) if !isReduced =>
+ <dt>Migration</dt>
+ <dd class="cmt">{ bodyToHtml(migration) }</dd>
+ case _ => NodeSeq.Empty
+ }
+
+ val mainComment: NodeSeq = mbr.comment match {
+ case Some(comment) if (! isReduced) =>
+ def orEmpty[T](it: Iterable[T])(gen: =>NodeSeq): NodeSeq =
+ if (it.isEmpty) NodeSeq.Empty else gen
+
+ val example =
+ orEmpty(comment.example) {
+ <div class="block">Example{ if (comment.example.length > 1) "s" else ""}:
+ <ol>{
+ val exampleXml: List[NodeSeq] = for (ex <- comment.example) yield
+ <li class="cmt">{ bodyToHtml(ex) }</li>
+ exampleXml.reduceLeft(_ ++ Text(", ") ++ _)
+ }</ol>
+ </div>
+ }
+
+ val version: NodeSeq =
+ orEmpty(comment.version) {
+ <dt>Version</dt>
+ <dd>{ for(body <- comment.version.toList) yield bodyToHtml(body) }</dd>
+ }
+
+ val sinceVersion: NodeSeq =
+ orEmpty(comment.since) {
+ <dt>Since</dt>
+ <dd>{ for(body <- comment.since.toList) yield bodyToHtml(body) }</dd>
+ }
+
+ val note: NodeSeq =
+ orEmpty(comment.note) {
+ <dt>Note</dt>
+ <dd>{
+ val noteXml: List[NodeSeq] = for(note <- comment.note ) yield <span class="cmt">{bodyToHtml(note)}</span>
+ noteXml.reduceLeft(_ ++ Text(", ") ++ _)
+ }</dd>
+ }
+
+ val seeAlso: NodeSeq =
+ orEmpty(comment.see) {
+ <dt>See also</dt>
+ <dd>{
+ val seeXml: List[NodeSeq] = for(see <- comment.see ) yield <span class="cmt">{bodyToHtml(see)}</span>
+ seeXml.reduceLeft(_ ++ _)
+ }</dd>
+ }
+
+ val exceptions: NodeSeq =
+ orEmpty(comment.throws) {
+ <dt>Exceptions thrown</dt>
+ <dd>{
+ val exceptionsXml: List[NodeSeq] =
+ for((name, body) <- comment.throws.toList.sortBy(_._1) ) yield
+ <span class="cmt">{bodyToHtml(body)}</span>
+ exceptionsXml.reduceLeft(_ ++ Text("") ++ _)
+ }</dd>
+ }
+
+ val todo: NodeSeq =
+ orEmpty(comment.todo) {
+ <dt>To do</dt>
+ <dd>{
+ val todoXml: List[NodeSeq] = (for(todo <- comment.todo ) yield <span class="cmt">{bodyToHtml(todo)}</span> )
+ todoXml.reduceLeft(_ ++ _)
+ }</dd>
+ }
+
+ example ++ version ++ sinceVersion ++ exceptions ++ todo ++ note ++ seeAlso
+
+ case _ => NodeSeq.Empty
+ }
+ // end attributes block vals ---
+
+ val attributesInfo = implicitInformation ++ attributes ++ definitionClasses ++ fullSignature ++ selfType ++ annotations ++ deprecation ++ migration ++ sourceLink ++ mainComment
+ val attributesBlock =
+ if (attributesInfo.isEmpty)
+ NodeSeq.Empty
+ else
+ <dl class="attributes block"> { attributesInfo }</dl>
+
+ val linearization = mbr match {
+ case dtpl: DocTemplateEntity if isSelf && !isReduced && dtpl.linearizationTemplates.nonEmpty =>
+ <div class="toggleContainer block">
+ <span class="toggle">Linear Supertypes</span>
+ <div class="superTypes hiddenContent">{
+ typesToHtml(dtpl.linearizationTypes, hasLinks = true, sep = scala.xml.Text(", "))
+ }</div>
+ </div>
+ case _ => NodeSeq.Empty
+ }
+
+ val subclasses = mbr match {
+ case dtpl: DocTemplateEntity if isSelf && !isReduced =>
+ val subs = mutable.HashSet.empty[DocTemplateEntity]
+ def transitive(dtpl: DocTemplateEntity) {
+ for (sub <- dtpl.directSubClasses if !(subs contains sub)) {
+ subs add sub
+ transitive(sub)
+ }
+ }
+ transitive(dtpl)
+ if (subs.nonEmpty)
+ <div class="toggleContainer block">
+ <span class="toggle">Known Subclasses</span>
+ <div class="subClasses hiddenContent">{
+ templatesToHtml(subs.toList.sorted(Entity.EntityOrdering), scala.xml.Text(", "))
+ }</div>
+ </div>
+ else NodeSeq.Empty
+ case _ => NodeSeq.Empty
+ }
+
+ def createDiagram(f: DocTemplateEntity => Option[Diagram], description: String, id: String): NodeSeq =
+ if (s.docDiagrams.value) mbr match {
+ case dtpl: DocTemplateEntity if isSelf && !isReduced =>
+ val diagram = f(dtpl)
+ if (diagram.isDefined) {
+ val diagramSvg = generator.generate(diagram.get, tpl, this)
+ if (diagramSvg != NodeSeq.Empty) {
+ <div class="toggleContainer block diagram-container" id={ id + "-container"}>
+ <span class="toggle diagram-link">{ description }</span>
+ <div class="diagram" id={ id }>{ diagramSvg }</div>
+ <div id="diagram-controls" class="hiddenContent">
+ <button id="diagram-zoom-out" class="diagram-btn"><i class="material-icons">&#xE15B;</i></button>
+ <button id="diagram-zoom-in" class="diagram-btn"><i class="material-icons">&#xE145;</i></button>
+ <button title="Toggle full-screen" id="diagram-fs" class="diagram-btn to-full"><i class="material-icons">&#xE5D0;</i></button>
+ </div>
+ </div>
+ } else NodeSeq.Empty
+ } else NodeSeq.Empty
+ case _ => NodeSeq.Empty
+ } else NodeSeq.Empty // diagrams not generated
+
+ val typeHierarchy = createDiagram(_.inheritanceDiagram, "Type Hierarchy", "inheritance-diagram")
+ val contentHierarchy = createDiagram(_.contentDiagram, "Content Hierarchy", "content-diagram")
+
+ memberComment ++ authorComment ++ paramComments ++ attributesBlock ++ linearization ++ subclasses ++ typeHierarchy ++ contentHierarchy
+ }
+
+ def boundsToHtml(hi: Option[TypeEntity], lo: Option[TypeEntity], hasLinks: Boolean): NodeSeq = {
+ def bound0(bnd: Option[TypeEntity], pre: String): NodeSeq = bnd match {
+ case None => NodeSeq.Empty
+ case Some(tpe) => scala.xml.Text(pre) ++ typeToHtml(tpe, hasLinks)
+ }
+ bound0(lo, " >: ") ++ bound0(hi, " <: ")
+ }
+
+ def visibility(mbr: MemberEntity): Option[comment.Paragraph] = {
+ import comment._
+ import comment.{ Text => CText }
+ mbr.visibility match {
+ case PrivateInInstance() =>
+ Some(Paragraph(CText("private[this]")))
+ case PrivateInTemplate(owner) if (owner == mbr.inTemplate) =>
+ Some(Paragraph(CText("private")))
+ case PrivateInTemplate(owner) =>
+ Some(Paragraph(Chain(List(CText("private["), EntityLink(comment.Text(owner.qualifiedName), LinkToTpl(owner)), CText("]")))))
+ case ProtectedInInstance() =>
+ Some(Paragraph(CText("protected[this]")))
+ case ProtectedInTemplate(owner) if (owner == mbr.inTemplate) =>
+ Some(Paragraph(CText("protected")))
+ case ProtectedInTemplate(owner) =>
+ Some(Paragraph(Chain(List(CText("protected["), EntityLink(comment.Text(owner.qualifiedName), LinkToTpl(owner)), CText("]")))))
+ case Public() =>
+ None
+ }
+ }
+
+ /** name, tparams, params, result */
+ def signature(mbr: MemberEntity, isSelf: Boolean, isReduced: Boolean = false): NodeSeq = {
+
+ def inside(hasLinks: Boolean, nameLink: String = ""): NodeSeq =
+ <xml:group>
+ <span class="modifier_kind">
+ <span class="modifier">{ mbr.flags.map(flag => inlineToHtml(flag.text) ++ scala.xml.Text(" ")) }</span>
+ <span class="kind">{ kindToString(mbr) }</span>
+ </span>
+ <span class="symbol">
+ {
+ val nameClass =
+ if (mbr.isImplicitlyInherited)
+ if (mbr.isShadowedOrAmbiguousImplicit)
+ "implicit shadowed"
+ else
+ "implicit"
+ else
+ "name"
+
+ val nameHtml = {
+ val value = if (mbr.isConstructor) tpl.name else mbr.name
+ val span = if (mbr.deprecation.isDefined)
+ <span class={ nameClass + " deprecated"} title={"Deprecated: "+bodyToStr(mbr.deprecation.get)}>{ value }</span>
+ else
+ <span class={ nameClass }>{ value }</span>
+ val encoded = scala.reflect.NameTransformer.encode(value)
+ if (encoded != value) {
+ span % new UnprefixedAttribute("title",
+ "gt4s: " + encoded +
+ span.attribute("title").map(
+ node => ". " + node
+ ).getOrElse(""),
+ scala.xml.Null)
+ } else {
+ span
+ }
+ }
+ if (!nameLink.isEmpty)
+ <a href={nameLink}>{nameHtml}</a>
+ else nameHtml
+ }{
+ def tparamsToHtml(mbr: Any): NodeSeq = mbr match {
+ case hk: HigherKinded =>
+ val tpss = hk.typeParams
+ if (tpss.isEmpty) NodeSeq.Empty else {
+ def tparam0(tp: TypeParam): NodeSeq =
+ <span name={ tp.name }>{ tp.variance + tp.name }{ tparamsToHtml(tp) }{ boundsToHtml(tp.hi, tp.lo, hasLinks)}</span>
+ def tparams0(tpss: List[TypeParam]): NodeSeq = (tpss: @unchecked) match {
+ case tp :: Nil => tparam0(tp)
+ case tp :: tps => tparam0(tp) ++ Text(", ") ++ tparams0(tps)
+ }
+ <span class="tparams">[{ tparams0(tpss) }]</span>
+ }
+ case _ => NodeSeq.Empty
+ }
+ tparamsToHtml(mbr)
+ }{
+ if (isReduced) NodeSeq.Empty else {
+ def paramsToHtml(vlsss: List[List[ValueParam]]): NodeSeq = {
+ def param0(vl: ValueParam): NodeSeq =
+ // notice the }{ in the next lines, they are necessary to avoid an undesired whitespace in output
+ <span name={ vl.name }>{
+ Text(vl.name)
+ }{ Text(": ") ++ typeToHtml(vl.resultType, hasLinks) }{
+ vl.defaultValue match {
+ case Some(v) => Text(" = ") ++ treeToHtml(v)
+ case None => NodeSeq.Empty
+ }
+ }</span>
+
+ def params0(vlss: List[ValueParam]): NodeSeq = vlss match {
+ case Nil => NodeSeq.Empty
+ case vl :: Nil => param0(vl)
+ case vl :: vls => param0(vl) ++ Text(", ") ++ params0(vls)
+ }
+ def implicitCheck(vlss: List[ValueParam]): NodeSeq = vlss match {
+ case vl :: vls => if(vl.isImplicit) { <span class="implicit">implicit </span> } else Text("")
+ case _ => Text("")
+ }
+ vlsss map { vlss => <span class="params">({implicitCheck(vlss) ++ params0(vlss) })</span> }
+ }
+ mbr match {
+ case cls: Class => paramsToHtml(cls.valueParams)
+ case ctr: Constructor => paramsToHtml(ctr.valueParams)
+ case dfe: Def => paramsToHtml(dfe.valueParams)
+ case _ => NodeSeq.Empty
+ }
+ }
+ }{ if (isReduced) NodeSeq.Empty else {
+ mbr match {
+ case tme: MemberEntity if (tme.isDef || tme.isVal || tme.isLazyVal || tme.isVar) =>
+ <span class="result">: { typeToHtml(tme.resultType, hasLinks) }</span>
+
+ case abt: MemberEntity with AbstractType =>
+ val b2s = boundsToHtml(abt.hi, abt.lo, hasLinks)
+ if (b2s != NodeSeq.Empty)
+ <span class="result">{ b2s }</span>
+ else NodeSeq.Empty
+
+ case alt: MemberEntity with AliasType =>
+ <span class="result"> = { typeToHtml(alt.alias, hasLinks) }</span>
+
+ case tpl: MemberTemplateEntity if !tpl.parentTypes.isEmpty =>
+ <span class="result"> extends { typeToHtml(tpl.parentTypes.map(_._2), hasLinks) }</span>
+
+ case _ => NodeSeq.Empty
+ }
+ }}
+ </span>
+ </xml:group>
+ mbr match {
+ case dte: DocTemplateEntity if !isSelf =>
+ permalink(dte, isSelf) ++ { inside(hasLinks = true, nameLink = relativeLinkTo(dte)) }
+ case _ if isSelf =>
+ <h4 id="signature" class="signature">{ inside(hasLinks = true) }</h4>
+ case _ =>
+ permalink(mbr) ++ { inside(hasLinks = true) }
+ }
+
+ }
+
+ /** */
+ def treeToHtml(tree: TreeEntity): NodeSeq = {
+
+ /** Makes text good looking in the html page : newlines and basic indentation,
+ * You must change this function if you want to improve pretty printing of default Values
+ */
+ def codeStringToXml(text: String): NodeSeq = {
+ var goodLookingXml: NodeSeq = NodeSeq.Empty
+ var indent = 0
+ for (c <- text) c match {
+ case '{' => indent+=1
+ goodLookingXml ++= Text("{")
+ case '}' => indent-=1
+ goodLookingXml ++= Text("}")
+ case '\n' =>
+ goodLookingXml++= <br/> ++ indentation
+ case _ => goodLookingXml ++= Text(c.toString)
+ }
+ def indentation:NodeSeq = {
+ var indentXml = NodeSeq.Empty
+ for (x <- 1 to indent) indentXml ++= Text("&nbsp;&nbsp;")
+ indentXml
+ }
+ goodLookingXml
+ }
+
+ var index = 0
+ val str = tree.expression
+ val length = str.length
+ var myXml: NodeSeq = NodeSeq.Empty
+ for ((from, (member, to)) <- tree.refEntity.toSeq) {
+ if (index < from) {
+ myXml ++= codeStringToXml(str.substring(index,from))
+ index = from
+ }
+ if (index == from) {
+ member match {
+ case mbr: DocTemplateEntity =>
+ val link = relativeLinkTo(mbr)
+ myXml ++= <span class="name"><a href={link}>{str.substring(from, to)}</a></span>
+ case mbr: MemberEntity =>
+ val anchor = "#" + mbr.signature
+ val link = relativeLinkTo(mbr.inTemplate)
+ myXml ++= <span class="name"><a href={link ++ anchor}>{str.substring(from, to)}</a></span>
+ }
+ index = to
+ }
+ }
+
+ if (index <= length-1)
+ myXml ++= codeStringToXml(str.substring(index, length ))
+
+ if (length < 36)
+ <span class="symbol">{ myXml }</span>
+ else
+ <span class="defval" name={ myXml }>{ "..." }</span>
+ }
+
+ private def argumentsToHtml(argss: List[ValueArgument]): NodeSeq = {
+ def argumentsToHtml0(argss: List[ValueArgument]): NodeSeq = argss match {
+ case Nil => NodeSeq.Empty
+ case arg :: Nil => argumentToHtml(arg)
+ case arg :: args => argumentToHtml(arg) ++ scala.xml.Text(", ") ++ argumentsToHtml0(args)
+ }
+ <span class="args">({ argumentsToHtml0(argss) })</span>
+ }
+
+ private def argumentToHtml(arg: ValueArgument): NodeSeq = {
+ <span>
+ {
+ arg.parameter match {
+ case Some(param) => Text(param.name + " = ")
+ case None => NodeSeq.Empty
+ }
+ }
+ { treeToHtml(arg.value) }
+ </span>
+ }
+
+ private def bodyToStr(body: comment.Body): String =
+ body.blocks flatMap (blockToStr(_)) mkString ""
+
+ private def blockToStr(block: comment.Block): String = block match {
+ case comment.Paragraph(in) => inlineToStr(in)
+ case _ => block.toString
+ }
+
+ private def inlineToStr(inl: comment.Inline): String = inl match {
+ case comment.Chain(items) => items flatMap (inlineToStr(_)) mkString ""
+ case comment.Italic(in) => inlineToStr(in)
+ case comment.Bold(in) => inlineToStr(in)
+ case comment.Underline(in) => inlineToStr(in)
+ case comment.Monospace(in) => inlineToStr(in)
+ case comment.Text(text) => text
+ case comment.Summary(in) => inlineToStr(in)
+ case _ => inl.toString
+ }
+
+ private def typeToHtmlWithStupidTypes(tpl: TemplateEntity, superTpl: TemplateEntity, superType: TypeEntity): NodeSeq =
+ if (tpl.universe.settings.useStupidTypes.value)
+ superTpl match {
+ case dtpl: DocTemplateEntity =>
+ val sig = signature(dtpl, isSelf = false, isReduced = true) \ "_"
+ sig
+ case tpl: TemplateEntity =>
+ Text(tpl.name)
+ }
+ else
+ typeToHtml(superType, hasLinks = true)
+
+ private def constraintToHtml(constraint: Constraint): NodeSeq = constraint match {
+ case ktcc: KnownTypeClassConstraint =>
+ scala.xml.Text(ktcc.typeExplanation(ktcc.typeParamName) + " (" + ktcc.typeParamName + ": ") ++
+ templateToHtml(ktcc.typeClassEntity) ++ scala.xml.Text(")")
+ case tcc: TypeClassConstraint =>
+ scala.xml.Text(tcc.typeParamName + " is ") ++
+ <a href="http://stackoverflow.com/questions/2982276/what-is-a-context-bound-in-scala" target="_blank">
+ context-bounded</a> ++ scala.xml.Text(" by " + tcc.typeClassEntity.qualifiedName + " (" + tcc.typeParamName + ": ") ++
+ templateToHtml(tcc.typeClassEntity) ++ scala.xml.Text(")")
+ case impl: ImplicitInScopeConstraint =>
+ scala.xml.Text("an implicit value of type ") ++ typeToHtml(impl.implicitType, hasLinks = true) ++ scala.xml.Text(" is in scope")
+ case eq: EqualTypeParamConstraint =>
+ scala.xml.Text(eq.typeParamName + " is " + eq.rhs.name + " (" + eq.typeParamName + " =:= ") ++
+ typeToHtml(eq.rhs, hasLinks = true) ++ scala.xml.Text(")")
+ case bt: BoundedTypeParamConstraint =>
+ scala.xml.Text(bt.typeParamName + " is a superclass of " + bt.lowerBound.name + " and a subclass of " +
+ bt.upperBound.name + " (" + bt.typeParamName + " >: ") ++
+ typeToHtml(bt.lowerBound, hasLinks = true) ++ scala.xml.Text(" <: ") ++
+ typeToHtml(bt.upperBound, hasLinks = true) ++ scala.xml.Text(")")
+ case lb: LowerBoundedTypeParamConstraint =>
+ scala.xml.Text(lb.typeParamName + " is a superclass of " + lb.lowerBound.name + " (" + lb.typeParamName + " >: ") ++
+ typeToHtml(lb.lowerBound, hasLinks = true) ++ scala.xml.Text(")")
+ case ub: UpperBoundedTypeParamConstraint =>
+ scala.xml.Text(ub.typeParamName + " is a subclass of " + ub.upperBound.name + " (" + ub.typeParamName + " <: ") ++
+ typeToHtml(ub.upperBound, hasLinks = true) ++ scala.xml.Text(")")
+ }
+}
+
+object EntityPage {
+ def apply(
+ uni: doc.Universe,
+ gen: DiagramGenerator,
+ docTpl: DocTemplateEntity,
+ rep: ScalaDocReporter
+ ): EntityPage = new EntityPage {
+ def universe = uni
+ def generator = gen
+ def tpl = docTpl
+ def reporter = rep
+ }
+}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Index.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Index.scala
index 1aa1241847..8204f413fd 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/page/Index.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Index.scala
@@ -1,6 +1,6 @@
/* NSC -- new Scala compiler
* Copyright 2007-2013 LAMP/EPFL
- * @author David Bernard, Manohar Jonnalagedda
+ * @author David Bernard, Manohar Jonnalagedda, Felix Mulder
*/
package scala.tools.nsc
@@ -12,115 +12,60 @@ import model._
import scala.collection._
import scala.xml._
-class Index(universe: doc.Universe, val index: doc.Index) extends HtmlPage {
+class Index(universe: doc.Universe, val index: doc.Index, rep: ScalaDocReporter) extends HtmlPage {
+
+ def reporter = rep
def path = List("index.html")
- def title = {
- val s = universe.settings
- ( if (!s.doctitle.isDefault) s.doctitle.value else "" ) +
- ( if (!s.docversion.isDefault) (" " + s.docversion.value) else "" )
- }
+ def title = ""
val headers =
<xml:group>
<link href={ relativeLinkTo{List("index.css", "lib")} } media="screen" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src={ relativeLinkTo{List("jquery.js", "lib")} }></script>
<script type="text/javascript" src={ relativeLinkTo{List("index.js", "lib")} }></script>
+ <script type="text/javascript" src="index.js"></script>
<script type="text/javascript" src={ relativeLinkTo{List("scheduler.js", "lib")} }></script>
</xml:group>
val body =
<body>
- { browser }
- <div id="content" class="ui-layout-center">
+ { search }
+ <div id="search-results">
+ <div id="results-content">
+ <div id="entity-results"></div>
+ <div id="member-results"></div>
+ </div>
+ </div>
+ <div id="content" style="-webkit-overflow-scrolling: touch;">
<iframe id="template" name="template" src={ relativeLinkTo{List("package.html")} }/>
</div>
</body>
- def letters: NodeSeq =
- '_' +: ('a' to 'z') map {
- char => {
- val label = if (char == '_') '#' else char.toUpper
-
- index.firstLetterIndex.get(char) match {
- case Some(_) =>
- <a target="template" href={ "index/index-" + char + ".html" }>{
- label
- }</a>
- case None => <span>{ label }</span>
- }
- }
- }
-
- def deprecated: NodeSeq = if (index.hasDeprecatedMembers)
- <a target="template" href="deprecated-list.html">deprecated</a>
- else
- <span>deprecated</span>
-
- def browser =
- <div id="browser" class="ui-layout-west">
- <div class="ui-west-center">
- <div id="filter">
- <div id="textfilter"></div>
- <div id="letters">{ letters } &#8211; { deprecated }</div>
- </div>
- <div class="pack" id="tpl">{
- def packageElem(pack: model.Package): NodeSeq = {
- <xml:group>
- { if (!pack.isRootPackage)
- <a class="tplshow" href={ relativeLinkTo(pack) } target="template">{ pack.qualifiedName }</a>
- else NodeSeq.Empty
- }
- <ol class="templates">{
- val tpls: Map[String, Seq[DocTemplateEntity]] =
- (pack.templates collect {
- case t: DocTemplateEntity if !t.isPackage && !universe.settings.hardcoded.isExcluded(t.qualifiedName) => t
- }) groupBy (_.name)
-
- val placeholderSeq: NodeSeq = <div class="placeholder"></div>
-
- def createLink(entity: DocTemplateEntity, includePlaceholder: Boolean, includeText: Boolean) = {
- val entityType = kindToString(entity)
- val linkContent = (
- { if (includePlaceholder) placeholderSeq else NodeSeq.Empty }
- ++
- { if (includeText) <span class="tplLink">{ Text(packageQualifiedName(entity)) }</span> else NodeSeq.Empty }
- )
- <a class="tplshow" href={ relativeLinkTo(entity) } target="template"><span class={ entityType }>({ Text(entityType) })</span>{ linkContent }</a>
- }
-
- for (tn <- tpls.keySet.toSeq sortBy (_.toLowerCase)) yield {
- val entities = tpls(tn)
- val row = (entities find (e => e.isPackage || e.isObject), entities find (e => e.isTrait || e.isClass))
-
- val itemContents = row match {
- case (Some(obj), None) => createLink(obj, includePlaceholder = true, includeText = true)
-
- case (maybeObj, Some(template)) =>
- val firstLink = maybeObj match {
- case Some(obj) => createLink(obj, includePlaceholder = false, includeText = false)
- case None => placeholderSeq
- }
-
- firstLink ++ createLink(template, includePlaceholder = false, includeText = true)
-
- case _ => // FIXME: this default case should not be necessary. For some reason AnyRef is not a package, object, trait, or class
- val entry = entities.head
- placeholderSeq ++ createLink(entry, includePlaceholder = false, includeText = true)
- }
-
- <li title={ entities.head.qualifiedName }>{ itemContents }</li>
- }
- }</ol>
- <ol class="packages"> {
- for (sp <- pack.packages sortBy (_.name.toLowerCase)) yield
- <li class="pack" title={ sp.qualifiedName }>{ packageElem(sp) }</li>
- }</ol>
- </xml:group>
- }
- packageElem(universe.rootPackage)
- }</div></div><script src="index.js"></script>
+ def search =
+ <div id="search">
+ <span id="doc-title">
+ {universe.settings.doctitle.value}
+ <span id="doc-version">
+ {
+ val version = universe.settings.docversion.value
+
+ if (version.length > "XX.XX.XX-XXX".length) {
+ reporter.warning(null,
+ s"doc-version ($version) is too long to be displayed in the webview")
+ ""
+ } else version
+ }
+ </span>
+ </span>
+ <span class="close-results"><span class="left">&lt;</span> Back</span>
+ <div id="textfilter">
+ <span class="input">
+ <input autocapitalize="none" placeholder="Search" id="index-input" type="text" accesskey="/"/>
+ <span class="clear">✖</span>
+ </span>
+ </div>
</div>
def packageQualifiedName(ety: DocTemplateEntity): String =
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/IndexScript.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/IndexScript.scala
index e3c94505ab..413c0a19d1 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/page/IndexScript.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/page/IndexScript.scala
@@ -1,16 +1,22 @@
/* NSC -- new Scala compiler
- * Copyright 2007-2013 LAMP/EPFL
- * @author David Bernard, Manohar Jonnalagedda
+ * Copyright 2007-2016 LAMP/EPFL
+ * @author David Bernard, Manohar Jonnalagedda, Felix Mulder
*/
-package scala.tools.nsc.doc.html.page
+package scala.tools.nsc.doc
+package html
+package page
import scala.tools.nsc.doc
import scala.tools.nsc.doc.model.{Package, DocTemplateEntity}
import scala.tools.nsc.doc.html.{Page, HtmlFactory}
-import scala.util.parsing.json.{JSONObject, JSONArray}
+import scala.util.parsing.json.{JSONObject, JSONArray, JSONType}
class IndexScript(universe: doc.Universe, index: doc.Index) extends Page {
+ import model._
+ import scala.tools.nsc.doc.base.comment.Text
+ import scala.collection.immutable.Map
+
def path = List("index.js")
override def writeFor(site: HtmlFactory) {
@@ -25,18 +31,21 @@ class IndexScript(universe: doc.Universe, index: doc.Index) extends Page {
val merged = mergeByQualifiedName(templates)
val ary = merged.keys.toList.sortBy(_.toLowerCase).map(key => {
- val pairs = merged(key).map(
- t => kindToString(t) -> relativeLinkTo(t)
- ) :+ ("name" -> key)
+ val pairs = merged(key).flatMap { t =>
+ Seq(
+ kindToString(t) -> relativeLinkTo(t),
+ "kind" -> kindToString(t),
+ "members" -> membersToJSON(t.members.filter(!_.isShadowedOrAmbiguousImplicit)))
+ }
- JSONObject(scala.collection.immutable.Map(pairs : _*))
+ JSONObject(Map(pairs : _*) + ("name" -> key))
})
pack.qualifiedName -> JSONArray(ary)
}
}).toSeq
- JSONObject(scala.collection.immutable.Map(pairs : _*))
+ JSONObject(Map(pairs : _*))
}
def mergeByQualifiedName(source: List[DocTemplateEntity]) = {
@@ -66,4 +75,65 @@ class IndexScript(universe: doc.Universe, index: doc.Index) extends Page {
}
}) : _*)
}
+
+ /** Returns the json representation of the supplied members */
+ def membersToJSON(entities: List[MemberEntity]): JSONType =
+ JSONArray(entities map memberToJSON)
+
+ private def memberToJSON(mbr: MemberEntity): JSONObject = {
+ /** This function takes a member and gets eventual parameters and the
+ * return type. For example, the definition:
+ * {{{ def get(key: A): Option[B] }}}
+ * Gets turned into: "(key: A): Option[B]"
+ */
+ def memberTail: MemberEntity => String = {
+ case d: Def => d
+ .valueParams //List[List[ValueParam]]
+ .map { params =>
+ params.map(p => p.name + ": " + p.resultType.name).mkString(", ")
+ }
+ .mkString("(", ")(", "): " + d.resultType.name)
+ case v: Val => ": " + v.resultType.name
+ }
+
+ /** This function takes a member entity and return all modifiers in a
+ * string, example:
+ * {{{ lazy val scalaProps: java.util.Properties }}}
+ * Gets turned into: "lazy val"
+ */
+ def memberKindToString(mbr: MemberEntity): String = {
+ val kind = mbr.flags.map(_.text.asInstanceOf[Text].text).mkString(" ")
+ val space = if (kind == "") "" else " "
+
+ kind + space + kindToString(mbr)
+ }
+
+ /** This function turns a member entity into a JSON object that the index.js
+ * script can use to render search results
+ */
+ def jsonObject(m: MemberEntity): JSONObject =
+ JSONObject(Map(
+ "label" -> m.definitionName.replaceAll(".*#", ""), // member name
+ "member" -> m.definitionName.replaceFirst("#", "."), // full member name
+ "tail" -> memberTail(m),
+ "kind" -> memberKindToString(m), // modifiers i.e. "abstract def"
+ "link" -> memberToUrl(m))) // permalink to the member
+
+ mbr match {
+ case d: Def => jsonObject(d)
+ case v: Val => jsonObject(v)
+ case m: MemberEntity =>
+ JSONObject(Map("member" -> m.definitionName, "error" -> "unsupported entity"))
+ }
+ }
+
+ def memberToUrl(mbr: MemberEntity): String = {
+ val path = templateToPath(mbr.inTemplate).reverse.mkString("/")
+ s"$path#${mbr.signature}"
+ }
+}
+
+object IndexScript {
+ def apply(universe: doc.Universe, index: doc.Index) =
+ new IndexScript(universe, index)
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/ReferenceIndex.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/ReferenceIndex.scala
index 84ee82f994..6780f17a8c 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/page/ReferenceIndex.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/page/ReferenceIndex.scala
@@ -12,7 +12,9 @@ package page
import doc.model._
-class ReferenceIndex(letter: Char, index: doc.Index, universe: Universe) extends HtmlPage {
+class ReferenceIndex(letter: Char, index: doc.Index, universe: Universe, rep: ScalaDocReporter) extends HtmlPage {
+
+ def reporter = rep
def path = List("index-"+letter+".html", "index")
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala
index 6e87f2b0a9..33c13c3bf3 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala
@@ -21,18 +21,17 @@ import model._
import model.diagram._
import diagram._
-class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemplateEntity) extends HtmlPage {
+class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemplateEntity, rep: ScalaDocReporter) extends HtmlPage {
- val path =
- templateToPath(tpl)
+ def reporter = rep
+
+ val path = templateToPath(tpl)
def title = {
val s = universe.settings
-
- tpl.name +
- ( if (!s.doctitle.isDefault) " - " + s.doctitle.value else "" ) +
- ( if (!s.docversion.isDefault) (" " + s.docversion.value) else "" ) +
- " - " + tpl.qualifiedName
+ ( if (!s.doctitle.isDefault) s.doctitle.value + " " else "" ) +
+ ( if (!s.docversion.isDefault) s.docversion.value else "" ) +
+ ( if ((!s.doctitle.isDefault || !s.docversion.isDefault) && tpl.qualifiedName != "_root_") " - " + tpl.qualifiedName else "" )
}
val headers =
@@ -116,9 +115,9 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
<h1>{ displayName }</h1>{
if (tpl.isPackage) NodeSeq.Empty else <h3>{companionAndPackage(tpl)}</h3>
}{ permalink(tpl) }
+ { signature(tpl, isSelf = true) }
</div>
- { signature(tpl, isSelf = true) }
{ memberToCommentHtml(tpl, tpl.inTemplate, isSelf = true) }
<div id="mbrsel">
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css
index 1260d860d0..b4c4af9dd2 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css
@@ -2,6 +2,17 @@
@font-face {
font-family: 'Lato';
font-style: normal;
+ font-weight: 100;
+ src: url('lato-v11-latin-regular.eot');
+ src: local('Lato'), local('Lato'),
+ url('lato-v11-latin-100.eot?#iefix') format('embedded-opentype'),
+ url('lato-v11-latin-100.woff') format('woff'),
+ url('lato-v11-latin-100.ttf') format('truetype');
+}
+
+@font-face {
+ font-family: 'Lato';
+ font-style: normal;
font-weight: 400;
src: url('lato-v11-latin-regular.eot');
src: local('Lato'), local('Lato'),
@@ -21,6 +32,27 @@
url('open-sans-v13-latin-regular.ttf') format('truetype');
}
+@font-face {
+ font-family: 'Source Code Pro';
+ font-style: normal;
+ font-weight: 400;
+ src: url('source-code-pro-v6-latin-regular.eot');
+ src: local('Source Code Pro'), local('SourceCodePro-Regular'),
+ url('source-code-pro-v6-latin-regular.eot?#iefix') format('embedded-opentype'),
+ url('source-code-pro-v6-latin-regular.woff') format('woff'),
+ url('source-code-pro-v6-latin-regular.ttf') format('truetype');
+}
+@font-face {
+ font-family: 'Source Code Pro';
+ font-style: normal;
+ font-weight: 700;
+ src: url('source-code-pro-v6-latin-700.eot');
+ src: local('Source Code Pro Bold'), local('SourceCodePro-Bold'),
+ url('source-code-pro-v6-latin-700.eot?#iefix') format('embedded-opentype'),
+ url('source-code-pro-v6-latin-700.woff') format('woff'),
+ url('source-code-pro-v6-latin-700.ttf') format('truetype');
+}
+
* {
color: inherit;
text-decoration: none;
@@ -31,18 +63,25 @@
a {
cursor: pointer;
+ text-decoration: none;
}
a:hover {
text-decoration: underline;
}
-.selected {
- background-color: #2E6D82;
+span.entity > a {
+ padding: 0.1em 0.5em;
+ margin-left: 0.2em;
+}
+
+span.entity > a.selected {
+ background-color: #C2D2DC;
+ border-radius: 0.2em;
}
html {
- background-color: #364550;
+ background-color: #f0f3f6;
box-sizing: border-box;
}
*, *:before, *:after {
@@ -56,51 +95,46 @@ textarea, input { outline: none; }
}
#browser {
- width: 16.75em;
+ width: 17.5em;
top: 0px;
left: 0;
bottom: 0px;
display: block;
position: fixed;
- background-color: #364550;
+ background-color: #f0f3f6;
}
#browser.full-screen {
- left: -15em;
+ left: -17.5em;
}
-#filter {
- position: absolute;
- display: block;
- right: 0;
- left: 0;
- top: 0;
- background-color: #364550; /* light gray */
- border-top:0;
- border-left:0;
- border-right:0;
- z-index: 99;
+#search {
+ background-color: #103a51; /* typesafe blue */
min-height: 5.5em;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 3em;
+ min-height: initial;
+ z-index: 103;
+ box-shadow: 0 0 4px rgba(0, 0, 0, 0.18), 0 4px 8px rgba(0, 0, 0, 0.28);
}
-#filter.scrolled {
- box-shadow: 0 0 8px rgba(0,0,0,0.5);
-}
-
-#filter > h1 {
+#search > h1 {
font-size: 2em;
position: absolute;
left: 0.25em;
top: 0.5em;
}
-#filter > h2 {
+#search > h2 {
position: absolute;
left: 3.8em;
top: 3em;
}
-#filter > img.scala-logo {
+#search > img.scala-logo {
width: 3em;
height: auto;
position: absolute;
@@ -108,22 +142,39 @@ textarea, input { outline: none; }
top: 0.43em;
}
-#filter > span.toggle-sidebar {
+#search > span.toggle-sidebar {
position: absolute;
top: 0.8em;
- right: 0.2em;
+ left: 0.2em;
color: #fff;
z-index: 99;
width: 1.5em;
height: 1.5em;
}
-#filter > span.toggle-sidebar:hover {
+#search > span#doc-title {
+ color: #fff;
+ position: absolute;
+ top: 0.8em;
+ left: 0;
+ width: 18em;
+ text-align: center;
+ cursor: pointer;
+ z-index: 2;
+}
+
+#search > span#doc-title > span#doc-version {
+ color: #c2c2c2;
+ font-weight: 100;
+ font-size: 0.72em;
+}
+
+#search > span.toggle-sidebar:hover {
cursor: pointer;
}
/* Pseudo element replacing UTF8-symbol "Trigram From Heaven" */
-#filter > span.toggle-sidebar:before {
+#search > span.toggle-sidebar:before {
position: absolute;
top: -0.45em;
left: 0.45em;
@@ -134,7 +185,7 @@ textarea, input { outline: none; }
box-shadow: 0 0.8em 0 1px #fff, 0 1.1em 0 1px #fff, 0 1.4em 0 1px #fff;
}
-#filter > span.toggle-sidebar:hover:before {
+#search > span.toggle-sidebar:hover:before {
-webkit-box-shadow: 0 0.8em 0 1px #c2c2c2, 0 1.1em 0 1px #c2c2c2, 0 1.4em 0 1px #c2c2c2;
box-shadow: 0 0.8em 0 1px #c2c2c2, 0 1.1em 0 1px #c2c2c2, 0 1.4em 0 1px #c2c2c2;
}
@@ -149,20 +200,29 @@ textarea, input { outline: none; }
}
#textfilter {
- position: relative;
+ position: absolute;
+ top: 0.5em;
+ bottom: 0.8em;
+ left: 0;
+ right: 0;
display: block;
- height: 20px;
- margin-top: 0.5em;
- margin-bottom: 0.8em;
+ height: 2em;
}
#textfilter > .input {
+ position: relative;
display: block;
+ padding: 0.2em;
+ max-width: 48.5em;
+ margin: 0 auto;
+}
+
+#textfilter > .input > i#search-icon {
+ color: rgba(255,255,255, 0.4);
position: absolute;
- top: 0;
- left: 0;
- padding: 0.2em 1.8em 0.2em 0.5em;
- width: 100%;
+ left: 0.34em;
+ top: 0.3em;
+ font-size: 1.3rem;
}
#textfilter > span.toggle {
@@ -199,29 +259,46 @@ textarea, input { outline: none; }
font-family: "Open Sans";
font-size: 0.85em;
height: 2em;
- padding: 0 0.5em;
+ padding: 0 0 0 2.1em;
color: #fff;
width: 100%;
border-radius: 0.2em;
background: rgba(255, 255, 255, 0.2);
}
+
+#textfilter > .input > input::-webkit-input-placeholder {
+ color: rgba(255, 255, 255, 0.4);
+}
+
+#textfilter > .input > input::-moz-placeholder {
+ color: rgba(255, 255, 255, 0.4);
+}
+
+#textfilter > .input > input:-ms-input-placeholder {
+ color: rgba(255, 255, 255, 0.4);
+}
+
+#textfilter > .input > input:-moz-placeholder {
+ color: rgba(255, 255, 255, 0.4);
+}
+
#focusfilter > .focusremove:hover {
text-decoration: none;
}
-#textfilter > .clear {
+#textfilter > .input > .clear {
display: none;
position: absolute;
font-size: 0.9em;
- top: 0.53em;
- right: 1.8em;
+ top: 0.7em;
+ right: 0.1em;
height: 23px;
width: 21px;
color: rgba(255, 255, 255, 0.4);
}
-#textfilter > .clear:hover {
+#textfilter > .input > .clear:hover {
cursor: pointer;
color: #fff;
}
@@ -230,11 +307,13 @@ textarea, input { outline: none; }
font-size: 0.9em;
position: relative;
text-align: center;
- display: block;
+ display: none;
padding: 0.6em;
background-color: #f16665;
color: #fff;
- margin-top: 0.65em;
+ margin: 3.9em 0.55em 0 0.35em;
+ border-radius: 0.2em;
+ z-index: 1;
}
#focusfilter .focuscoll {
@@ -252,7 +331,7 @@ textarea, input { outline: none; }
z-index: 99;
bottom: 0.5em;
left: 0;
- width: 16.75em;
+ width: 17.25em;
}
#kindfilter {
@@ -300,177 +379,344 @@ textarea, input { outline: none; }
color: #bbb;
}
-#tpl {
- font-size: 0.8em;
- overflow: auto;
+div#content-container {
+ position: absolute;
+ top: 0;
right: 0;
- left: 0;
bottom: 0;
- top: 6.9em !important;
- position: absolute;
+ left: 0;
+ z-index: 100;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+div#content-container > div#content {
+ -webkit-overflow-scrolling: touch;
display: block;
- background-color: #364550;
- padding-top: 0.3em;
+ overflow-y: auto;
+ max-width: 1140px;
+ margin: 5em auto 0;
}
-#tpl.packfocused {
- top: 9.5em !important;
+div#search-results {
+ color: #103a51;
+ position: absolute;
+ left: 0;
+ top: 3em;
+ right: 0;
+ bottom: 0;
+ background-color: rgb(240, 243, 246);
+ z-index: 101;
+ overflow-x: hidden;
+ display: none;
+ padding: 1em;
+ -webkit-overflow-scrolling: touch;
}
-#tpl .packfocus,
-#tpl .packhide {
- display: block;
- float: right;
- font-weight: normal;
- color: #f16665;
+div#search > span.close-results {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ position: fixed;
+ top: 0.8em;
+ left: 1em;
+ color: #fff;
+ display: none;
+ z-index: 1;
}
-#tpl .packfocus:hover,
-#tpl .packhide:hover {
- text-decoration: none;
- color: #53cdec;
+div#search > span.close-results:hover {
+ cursor: pointer;
+}
+
+div#results-content {
+ max-width: 1140px;
+ margin: 0 auto;
}
-#tpl .packages {
+div#results-content > span.search-text {
+ margin-left: 1em;
+ font-size: 1.2em;
+ float: left;
width: 100%;
- padding-left: 0;
- overflow-x: hidden;
}
-#tpl .packages > ol {
- color: #fff;
- background-color: #364550;
- padding-left: 0;
+div#results-content > span.search-text > span.query-str {
+ font-weight: 900;
}
-#tpl .packages > li > a {
- padding: 0px 5px;
+div#results-content > div > h1.result-type {
+ font-size: 1.5em;
+ margin: 1em 0 0.3em;
+ font-family: "Open Sans";
+ font-weight: 300;
+ border-bottom: 1px solid #103a51;
}
-#tpl .packages > li > a.tplshow {
- display: block;
+div#results-content > div#entity-results {
+ float: left;
+ width: 50%;
+ padding: 1em;
+ display: inline;
+}
+
+div#results-content > div#member-results {
+ float: left;
+ width: 50%;
+ padding: 1em;
+ display: inline;
+}
+
+div#results-content > div#member-results > a.package,
+div#results-content > div#entity-results > a.package {
+ font-size: 1em;
+ margin: 0 0 1em 0;
color: #f16665;
- font-weight: bold;
- display: block;
+ cursor: pointer;
}
-#tpl .packages > li > a.tplshow:hover {
- color: #53cdec;
- text-decoration: none;
+div#results-content > div#member-results > ul.entities,
+div#results-content > div#entity-results > ul.entities {
+ list-style-type: none;
+ padding-left: 0;
}
-#tpl .packages a.tplshow > .type-circle {
+div#results-content > div#member-results > ul.entities > li,
+div#results-content > div#entity-results > ul.entities > li {
+ margin: 0.5em 0;
+}
+
+div#results-content > div#member-results > ul.entities > li > .icon,
+div#results-content > div#entity-results > ul.entities > li > .icon {
float: left;
- border: 1px solid rgba(255, 255, 255, 0.4);
- height: 0.8rem;
- width: 0.8rem;
- border-radius: 0.8rem;
- color: #efefef;
- margin-top: 0.16em;
- margin-right: 0.1em;
- position: relative;
- font-size: 0.8em;
- line-height: 0.9;
- font-family: Arial, sans-serif;
- text-align: center;
- display: table-cell;
- vertical-align: middle;
+ display: inline;
+ height: 1em;
+ width: 1em;
+ margin: 0.23em 0 0;
+ cursor: pointer;
}
+div#results-content > div#member-results > ul.entities > li > .icon.class,
+div#results-content > div#entity-results > ul.entities > li > .icon.class {
+ background: url("class.svg") no-repeat center;
+ background-size: 1em 1em;
+}
-#tpl .packages a.tplshow > .type-circle > span {
- font-size: 0.9em;
+div#results-content > div#member-results > ul.entities > li > .icon.trait,
+div#results-content > div#entity-results > ul.entities > li > .icon.trait {
+ background: url("trait.svg") no-repeat center;
+ background-size: 1em 1em;
}
-#tpl .packages a.tplshow > .type-circle.class {
- background-color: #316555;
+div#results-content > div#member-results > ul.entities > li > .icon.object,
+div#results-content > div#entity-results > ul.entities > li > .icon.object {
+ background: url("object.svg") no-repeat center;
+ background-size: 1em 1em;
}
-#tpl .packages a.tplshow > .type-circle.object {
- background-color: #103A51;
+div#results-content > div#member-results > ul.entities > li > span.entity,
+div#results-content > div#entity-results > ul.entities > li > span.entity {
+ font-size: 1.1em;
+ font-weight: 900;
}
-#tpl .packages a.tplshow > .type-circle.trait {
- background-color: #19AACF;
+div#results-content > div#member-results > ul.entities > li > ul.members,
+div#results-content > div#entity-results > ul.entities > li > ul.members {
+ margin-top: 0.5em;
+ list-style-type: none;
+ font-size: 0.85em;
+ margin-left: 0.2em;
}
-#tpl ol > li.pack {
- padding: 3px 5px;
- min-height: 14px;
- background-color: #364550;
+div#results-content > div#member-results > ul.entities > li > ul.members > li,
+div#results-content > div#entity-results > ul.entities > li > ul.members > li {
+ margin: 0.5em 0;
}
-#tpl > ol > ol > li > a:hover {
- text-decoration: none;
- color: #53cdec;
+div#results-content > div#member-results > ul.entities > li > ul.members > li > span.kind,
+div#results-content > div#member-results > ul.entities > li > ul.members > li > span.tail,
+div#results-content > div#entity-results > ul.entities > li > ul.members > li > span.kind,
+div#results-content > div#entity-results > ul.entities > li > ul.members > li > span.tail {
+ margin-right: 0.6em;
+ font-family: "Source Code Pro";
}
-#tpl ol > li {
- display: block;
+div#results-content > div#member-results > ul.entities > li > ul.members > li > span.kind {
+ font-weight: 600;
+}
+
+div#results-content > div#member-results > ul.entities > li > ul.members > li > a.label,
+div#results-content > div#entity-results > ul.entities > li > ul.members > li > a.label {
+ color: #2C3D9B;
+ font-family: "Source Code Pro";
+}
+
+/** Scrollpane settings needed for jquery.scrollpane.min.js */
+.jspContainer {
+ overflow: hidden;
+ position: relative;
+}
+
+.jspPane {
+ position: absolute;
+}
+
+.jspVerticalBar {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 0.6em;
+ height: 100%;
+ background: transparent;
+}
+
+.jspHorizontalBar {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 16px;
+ background: red;
+}
+
+.jspCap {
+ display: none;
}
-#tpl .templates > li {
- padding-left: 5px;
- min-height: 1.4em;
- width: 21em; /* tpl width == 20em */
+.jspHorizontalBar .jspCap {
+ float: left;
}
-#tpl ol > li .icon {
- padding-right: 5px;
- bottom: -2px;
+.jspTrack {
+ background: #f0f3f6;
position: relative;
}
-#tpl .templates div.placeholder {
- padding-right: 14px;
- width: 11px;
- display: inline-block;
+.jspDrag {
+ display: none;
+ background: rgba(0, 0, 0, 0.35);
+ position: relative;
+ top: 0;
+ left: 0;
+ cursor: pointer;
}
-#tpl .templates span.tplLink {
- padding-left: 7px;
+#tpl:hover .jspDrag {
+ display: block;
}
-#content {
- right: 0px;
- left: 16.75em;
- bottom: 0px;
- top: 0px;
- position: fixed;
+.jspHorizontalBar .jspTrack,
+.jspHorizontalBar .jspDrag {
+ float: left;
+ height: 100%;
+}
+
+.jspArrow {
+ background: #50506d;
+ text-indent: -20000px;
display: block;
- overflow-y: auto;
- -webkit-overflow-scrolling: touch;
- background-color: #fff;
- z-index: 100;
+ cursor: pointer;
+ padding: 0;
+ margin: 0;
}
-#content.full-screen {
- left: 1.7em;
+.jspArrow.jspDisabled {
+ cursor: default;
+ background: #80808d;
}
-#content.hide-filter {
- left: 1.5em;
+.jspVerticalBar .jspArrow {
+ height: 16px;
}
-#content > iframe {
- display: block;
+.jspHorizontalBar .jspArrow {
+ width: 16px;
+ float: left;
height: 100%;
- width: 100%;
}
-.ui-layout-pane {
- background: #FFF;
- overflow: auto;
+.jspVerticalBar .jspArrow:focus {
+ outline: none;
}
-.ui-layout-resizer {
- background-color: #ededee; /* light gray */
- border:1px solid #bbbbbb;
- border-top:0;
- border-bottom:0;
- border-left: 0;
+.jspCorner {
+ background: #eeeef4;
+ float: left;
+ height: 100%;
}
-.ui-layout-toggler {
- background: #AAA;
+/* CSS Hack for IE6 3 pixel bug */
+* html .jspCorner {
+ margin: 0 -3px 0 0;
+}
+
+/* Media query rules for smaller viewport */
+@media only screen /* Large screen with a small window */
+and (max-width: 1300px)
+{
+ #textfilter {
+ left: 17.8em;
+ right: 0.35em;
+ }
+
+ #textfilter .input {
+ max-width: none;
+ margin: 0;
+ }
+}
+
+@media only screen /* Large screen with a smaller window */
+and (max-width: 800px)
+{
+ div#results-content > div#entity-results {
+ width: 100%;
+ padding: 0em;
+ }
+
+ div#results-content > div#member-results {
+ width: 100%;
+ padding: 0em;
+ }
+}
+
+/* Media query rules specifically for mobile devices */
+@media
+screen /* HiDPI device like Nexus 5 */
+and (max-device-width: 360px)
+and (max-device-height: 640px)
+and (-webkit-device-pixel-ratio: 3)
+,
+screen /* Most mobile devices */
+and (max-device-width: 480px)
+and (orientation: portrait)
+,
+only screen /* iPhone 6 */
+and (max-device-width: 667px)
+and (-webkit-device-pixel-ratio: 2)
+{
+ div#content-container > div#content {
+ margin: 3.3em auto 0;
+ }
+
+ #search > span#doc-title {
+ width: 100%;
+ text-align: left;
+ padding-left: 0.7em;
+ top: 0.95em;
+ z-index: 1;
+ }
+
+ #search > div#textfilter {
+ z-index: 2;
+ }
+
+ #search > span#doc-title > span#doc-version {
+ display: none;
+ }
+
+ #textfilter {
+ left: 12.2em;
+ }
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js
index cad4072912..7ba18a26d9 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.js
@@ -1,119 +1,35 @@
// © 2009–2010 EPFL/LAMP
// code by Gilles Dubochet with contributions by Johannes Rudolph, "spiros", Marcin Kubala and Felix Mulder
-var topLevelTemplates = undefined;
-var topLevelPackages = undefined;
-
var scheduler = undefined;
-var kindFilterState = undefined;
-var focusFilterState = undefined;
-
var title = $(document).attr('title');
var lastFragment = "";
$(document).ready(function() {
- /* check if browser is mobile, if so hide class nav */
- if( /Android|webOS|Mobi|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
- $("#browser").toggleClass("full-screen");
- $("#content").toggleClass("full-screen");
- $("#letters").toggle();
- setTimeout(function() {
- $(".packages").hide();
- $("#kindfilter").hide();
- }, 4000);
- }
-
- $('iframe').bind("load", function(){
- try {
- var subtitle = $(this).contents().find('title').text();
- $(document).attr('title', (title ? title + " - " : "") + subtitle);
- } catch (e) {
- // Chrome doesn't allow reading the iframe's contents when
- // used on the local file system.
- }
- setUrlFragmentFromFrameSrc();
- });
-
- // workaround for IE's iframe sizing lack of smartness
- if($.browser.msie) {
- function fixIFrame() {
- $('iframe').height($(window).height() )
- }
- $('iframe').bind("load",fixIFrame)
- $('iframe').bind("resize",fixIFrame)
- }
+ // Clicking #doc-title returns the user to the root package
+ $("#doc-title").click(function() { document.location = toRoot + "index.html" });
scheduler = new Scheduler();
scheduler.addLabel("init", 1);
scheduler.addLabel("focus", 2);
scheduler.addLabel("filter", 4);
+ scheduler.addLabel("search", 5);
- prepareEntityList();
configureTextFilter();
- configureEntityList();
-
- setFrameSrcFromUrlFragment();
- // If the url fragment changes, adjust the src of iframe "template".
- $(window).bind('hashchange', function() {
- if(lastFragment != window.location.hash) {
- lastFragment = window.location.hash;
- setFrameSrcFromUrlFragment();
- }
+ $("#index-input").on("focus", function(e) {
+ $("#textfilter > .input > .clear").show();
});
- // Wait until page has loaded until binding input fields, setting fold all
- setTimeout(function() {
- configureKindFilter();
-
- $("#index-input").on("focus", function() {
- $("#textfilter > .clear").show();
- });
-
- $("#index-input").on("blur", function() {
- $("#textfilter > .clear").hide();
- });
- }, 1500);
+ $("#index-input").on("blur", function() {
+ setTimeout(function() {
+ $("#textfilter > .input > .clear").hide();
+ }, 10);
+ });
});
-// Set the iframe's src according to the fragment of the current url.
-// fragment = "#scala.Either" => iframe url = "scala/Either.html"
-// fragment = "#scala.Either@isRight:Boolean" => iframe url = "scala/Either.html#isRight:Boolean"
-// fragment = "#scalaz.iteratee.package@>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]" => iframe url = "scalaz/iteratee/package.html#>@>[E,A]=scalaz.iteratee.package.Iteratee[E,A]"
-function setFrameSrcFromUrlFragment() {
-
- function extractLoc(fragment) {
- var loc = fragment.split('@')[0].replace(/\./g, "/");
- if (loc.indexOf(".html") < 0) {
- loc += ".html";
- }
- return loc;
- }
-
- function extractMemberSig(fragment) {
- var splitIdx = fragment.indexOf('@');
- if (splitIdx < 0) {
- return;
- }
- return fragment.substr(splitIdx + 1);
- }
-
- var fragment = location.hash.slice(1);
- if (fragment) {
- var locWithMemeberSig = extractLoc(fragment);
- var memberSig = extractMemberSig(fragment);
- if (memberSig) {
- locWithMemeberSig += "#" + memberSig;
- }
- frames["template"].location.replace(location.protocol + locWithMemeberSig);
- } else {
- console.log("empty fragment detected");
- frames["template"].location.replace("package.html");
- }
-}
-
// Set the url fragment according to the src of the iframe "template".
// iframe url = "scala/Either.html" => url fragment = "#scala.Either"
// iframe url = "scala/Either.html#isRight:Boolean" => url fragment = "#scala.Either@isRight:Boolean"
@@ -146,83 +62,6 @@ function setUrlFragmentFromFrameSrc() {
var Index = {};
(function (ns) {
- function openLink(t, type) {
- var href;
- if (type == 'object') {
- href = t['object'];
- } else {
- href = t['class'] || t['trait'] || t['case class'] || t['type'];
- }
- return [
- '<a class="tplshow" target="template" href="',
- href,
- '"><div class="type-circle ',
- type,
- '"><span>',
- type.charAt(0).toLowerCase(),
- '</span></div>'
- ].join('');
- }
-
- function createPackageHeader(pack) {
- return [
- '<li class="pack">',
- '<a class="packfocus">focus</a><a class="packhide">hide</a>',
- '<a class="tplshow" target="template" href="',
- pack.replace(/\./g, '/'),
- '/package.html">',
- pack,
- '</a></li>'
- ].join('');
- };
-
- function createListItem(template) {
- var inner = '';
-
-
- if (template.object) {
- inner += openLink(template, 'object');
- }
-
- if (template['class'] || template['trait'] || template['case class'] || template['type']) {
- inner += (inner == '') ?
- '<div class="placeholder" />' : '</a>';
- inner += openLink(template, template['trait'] ? 'trait' : template['type'] ? 'type' : 'class');
- } else {
- inner += '<div class="placeholder"/>';
- }
-
- return [
- '<li>',
- inner,
- '<span class="tplLink">',
- template.name.replace(/^.*\./, ''),
- '</span></a></li>'
- ].join('');
- }
-
-
- ns.createPackageTree = function (pack, matched, focused) {
- var html = $.map(matched, function (child, i) {
- return createListItem(child);
- }).join('');
-
- var header;
- if (focused && pack == focused) {
- header = '';
- } else {
- header = createPackageHeader(pack);
- }
-
- return [
- '<ol class="packages">',
- header,
- '<ol class="templates">',
- html,
- '</ol></ol>'
- ].join('');
- }
-
ns.keys = function (obj) {
var result = [];
var key;
@@ -231,133 +70,157 @@ var Index = {};
}
return result;
}
+})(Index);
- var hiddenPackages = {};
-
- function subPackages(pack) {
- return $.grep($('#tpl ol.packages'), function (element, index) {
- var pack = $('li.pack > .tplshow', element).text();
- return pack.indexOf(pack + '.') == 0;
- });
- }
-
- ns.hidePackage = function (ol) {
- var selected = $('li.pack > .tplshow', ol).text();
- hiddenPackages[selected] = true;
-
- $('ol.templates', ol).hide();
-
- $.each(subPackages(selected), function (index, element) {
- $(element).hide();
- });
- }
-
- ns.showPackage = function (ol, state) {
- var selected = $('li.pack > .tplshow', ol).text();
- hiddenPackages[selected] = false;
+/* Handles all key presses while scrolling around with keyboard shortcuts in search results */
+function handleKeyNavigation() {
+ /** Iterates both back and forth among selected elements */
+ var EntityIterator = function (litems, ritems) {
+ var it = this;
+ this.index = -1;
+
+ this.items = litems;
+ this.litems = litems;
+ this.ritems = ritems;
+
+ if (litems.length == 0)
+ this.items = ritems;
+
+ /** Returns the next entry - if trying to select past last element, it
+ * returns the last element
+ */
+ it.next = function() {
+ it.index = Math.min(it.items.length - 1, it.index + 1);
+ return $(it.items[it.index]);
+ };
- $('ol.templates', ol).show();
+ /** Returns the previous entry - will return `undefined` instead if
+ * selecting up from first element
+ */
+ it.prev = function() {
+ it.index = Math.max(-1, it.index - 1);
+ return it.index == -1 ? undefined : $(it.items[it.index]);
+ };
- $.each(subPackages(selected), function (index, element) {
- $(element).show();
+ it.right = function() {
+ if (it.ritems.length != 0) {
+ it.items = it.ritems;
+ it.index = Math.min(it.index, it.items.length - 1);
+ }
+ return $(it.items[it.index]);
+ };
- // When the filter is in "packs" state,
- // we don't want to show the `.templates`
- var key = $('li.pack > .tplshow', element).text();
- if (hiddenPackages[key] || state == 'packs') {
- $('ol.templates', element).hide();
+ it.left = function() {
+ if (it.litems.length != 0) {
+ it.items = it.litems;
+ it.index = Math.min(it.index, it.items.length - 1);
}
- });
- }
+ return $(it.items[it.index]);
+ };
+ };
-})(Index);
+ /** Scroll helper, ensures that the selected elem is inside the viewport */
+ var Scroller = function ($container) {
+ scroller = this;
+ scroller.container = $container;
+
+ scroller.scrollDown = function($elem) {
+ var yPos = $elem.offset().top; // offset relative to viewport
+ if ($container.height() < yPos) {
+ $container.animate({
+ scrollTop: $container.scrollTop() + yPos - $("#search").height() - 10
+ }, 200);
+ }
+ };
-function configureEntityList() {
- kindFilterSync();
- configureHideFilter();
- configureFocusFilter();
- textFilter();
-}
+ scroller.scrollUp = function ($elem) {
+ var yPos = $elem.offset().top; // offset relative to viewport
+ if (yPos < $("#search").height()) {
+ $container.animate({
+ scrollTop: $container.scrollTop() + yPos - $("#search").height() - 10
+ }, 200);
+ }
+ };
-/**
- * Updates the list of entities (i.e. the content of the #tpl element) from the
- * raw form generated by Scaladoc to a form suitable for display. It configures
- * links to open in the right frame. Furthermore, it sets the two reference
- * top-level entities lists (topLevelTemplates and topLevelPackages) to serve
- * as reference for resetting the list when needed.
- *
- * Be advised: this function should only be called once, on page load.
- */
-function prepareEntityList() {
- $('#tpl li.pack > a.tplshow').attr("target", "template");
- $('#tpl li.pack')
- .prepend("<a class='packhide'>hide</a>")
- .prepend("<a class='packfocus'>focus</a>");
-}
+ scroller.scrollTop = function() {
+ $container.animate({
+ scrollTop: 0
+ }, 200);
+ }
+ };
-/* Handles all key presses while scrolling around with keyboard shortcuts in left panel */
-function keyboardScrolldownLeftPane() {
scheduler.add("init", function() {
$("#textfilter input").blur();
- var $items = $("#tpl li");
- $items.first().addClass('selected');
+ var items = new EntityIterator(
+ $("div#results-content > div#entity-results > ul.entities span.entity > a").toArray(),
+ $("div#results-content > div#member-results > ul.entities span.entity > a").toArray()
+ );
- $(window).bind("keydown", function(e) {
- var $old = $items.filter('.selected'),
- $new;
+ var scroller = new Scroller($("#search-results"));
- switch ( e.keyCode ) {
+ var $old = items.next();
+ $old.addClass("selected");
+ $(window).bind("keydown", function(e) {
+ switch ( e.keyCode ) {
case 9: // tab
- $old.removeClass('selected');
+ $old.removeClass("selected");
break;
case 13: // enter
- $old.removeClass('selected');
- var $url = $old.children().filter('a:last').attr('href');
- $("#template").attr("src",$url);
+ var href = $old.attr("href");
+ location.replace(href);
+ $old.click();
+ $("#textfilter input").attr("value", "");
break;
case 27: // escape
- $old.removeClass('selected');
- $(window).unbind(e);
- $("#textfilter input").focus();
+ $("#textfilter input").attr("value", "");
+ $("div#search-results").hide();
+ $("#search > span.close-results").hide();
+ $("#search > span#doc-title").show();
+ break;
+
+ case 37: // left
+ var oldTop = $old.offset().top;
+ $old.removeClass("selected");
+ $old = items.left();
+ $old.addClass("selected");
+ (oldTop - $old.offset().top < 0 ? scroller.scrollDown : scroller.scrollUp)($old);
break;
case 38: // up
- $new = $old.prev();
-
- if (!$new.length) {
- $new = $old.parent().prev();
+ $old.removeClass('selected');
+ $old = items.prev();
+
+ if ($old === undefined) { // scroll past top
+ $(window).unbind("keydown");
+ $("#textfilter input").focus();
+ scroller.scrollTop();
+ return false;
+ } else {
+ $old.addClass("selected");
+ scroller.scrollUp($old);
}
+ break;
- if ($new.is('ol') && $new.children(':last').is('ol')) {
- $new = $new.children().children(':last');
- } else if ($new.is('ol')) {
- $new = $new.children(':last');
- }
+ case 39: // right
+ var oldTop = $old.offset().top;
+ $old.removeClass("selected");
+ $old = items.right();
+ $old.addClass("selected");
+ (oldTop - $old.offset().top < 0 ? scroller.scrollDown : scroller.scrollUp)($old);
break;
case 40: // down
- $new = $old.next();
- if (!$new.length) {
- $new = $old.parent().parent().next();
- }
- if ($new.is('ol')) {
- $new = $new.children(':first');
- }
+ $old.removeClass("selected");
+ $old = items.next();
+ $old.addClass("selected");
+ scroller.scrollDown($old);
break;
}
-
- if ($new && $new.is('li')) {
- $old.removeClass('selected');
- $new.addClass('selected');
- } else if (e.keyCode == 38) {
- $(window).unbind(e);
- $("#textfilter input").focus();
- }
});
});
}
@@ -365,49 +228,43 @@ function keyboardScrolldownLeftPane() {
/* Configures the text filter */
function configureTextFilter() {
scheduler.add("init", function() {
- $("#filter").prepend("<span class='toggle-sidebar'></span>");
- $("#textfilter").append("<span class='input'><input placeholder='Filter' id='index-input' type='text' accesskey='/'/></span><span class='clear'>✖</span>");
var input = $("#textfilter input");
- resizeFilterBlock();
input.bind('keyup', function(event) {
- if (event.keyCode == 27) { // escape
- input.attr("value", "");
- }
- if (event.keyCode == 40) { // down arrow
- $(window).unbind("keydown");
- keyboardScrolldownLeftPane();
- return false;
- }
- textFilter();
- });
- input.bind('keydown', function(event) {
- if (event.keyCode == 9) { // tab
- $("#template").contents().find("#mbrsel-input").focus();
- input.attr("value", "");
- return false;
+ switch ( event.keyCode ) {
+ case 27: // escape
+ input.attr("value", "");
+ $("div#search-results").hide();
+ $("#search > span.close-results").hide();
+ $("#search > span#doc-title").show();
+ break;
+
+ case 38: // up arrow
+ return false;
+
+ case 40: // down arrow
+ $(window).unbind("keydown");
+ handleKeyNavigation();
+ return false;
}
- textFilter();
+
+ searchAll();
});
- input.focus(function(event) { input.select(); });
});
scheduler.add("init", function() {
- $("#textfilter > .clear").click(function(){
+ $("#textfilter > .input > .clear").click(function() {
$("#textfilter input").attr("value", "");
- textFilter();
- });
- $("#filter > span.toggle-sidebar").click(function() {
- $("#browser").toggleClass("full-screen");
- $("#content").toggleClass("full-screen");
- $(".packages").toggle();
- $("#letters").toggle();
- $("#kindfilter").toggle();
+ $("div#search-results").hide();
+ $("#search > span.close-results").hide();
+ $("#search > span#doc-title").show();
});
- $(".pack").scroll(function() {
- var scroll = $(".pack").scrollTop();
- if (scroll > 0)
- $("#filter").addClass("scrolled");
- else
- $("#filter").removeClass("scrolled");
+ });
+
+ scheduler.add("init", function() {
+ $("div#search > span.close-results").click(function() {
+ $("div#search-results").hide();
+ $("#search > span.close-results").hide();
+ $("#search > span#doc-title").show();
+ $("#textfilter input").attr("value", "");
});
});
}
@@ -425,196 +282,303 @@ function compilePattern(query) {
}
}
-// Filters all focused templates and packages. This function should be made less-blocking.
-// @param query The string of the query
-function textFilter() {
- var query = $("#textfilter input").attr("value") || '';
- var queryRegExp = compilePattern(query);
-
- // if we are filtering on types, then we have to display types
- // ("display packages only" is not possible when filtering)
- if (query !== "") {
- kindFilter("all");
- }
+/** Searches packages for entites matching the search query using a regex
+ *
+ * @param {[Object]} pack: package being searched
+ * @param {RegExp} regExp: a regular expression for finding matching entities
+ */
+function searchPackage(pack, regExp) {
+ scheduler.add("search", function() {
+ var entities = Index.PACKAGES[pack];
+ var matched = [];
+ var notMatching = [];
+
+ scheduler.add("search", function() {
+ searchMembers(entities, regExp, pack);
+ });
- // Three things trigger a reload of the left pane list:
- // typeof textFilter.lastQuery === "undefined" <-- first load, there is nothing yet in the left pane
- // textFilter.lastQuery !== query <-- the filter text has changed
- // focusFilterState != null <-- a package has been "focused"
- if ((typeof textFilter.lastQuery === "undefined") || (textFilter.lastQuery !== query) || (focusFilterState != null)) {
+ entities.forEach(function (elem) {
+ regExp.test(elem.name) ? matched.push(elem) : notMatching.push(elem);
+ });
- textFilter.lastQuery = query;
+ var results = {
+ "matched": matched,
+ "package": pack
+ };
- scheduler.clear("filter");
+ scheduler.add("search", function() {
+ handleSearchedPackage(results, regExp);
+ });
+ });
+}
- $('#tpl').html('');
+function searchMembers(entities, regExp, pack) {
+ var memDiv = document.getElementById("member-results");
+ var packLink = document.createElement("a");
+ packLink.className = "package";
+ packLink.appendChild(document.createTextNode(pack));
+ packLink.style.display = "none";
+ packLink.title = pack;
+ packLink.href = toRoot + urlFriendlyEntity(pack).replace(new RegExp("\\.", "g"), "/") + "/index.html";
+ memDiv.appendChild(packLink);
+
+ var entityUl = document.createElement("ul");
+ entityUl.className = "entities";
+ memDiv.appendChild(entityUl);
+
+ entities.forEach(function(entity) {
+ var entityLi = document.createElement("li");
+ var name = entity.name.split('.').pop()
+
+ var iconElem = document.createElement("a");
+ iconElem.className = "icon " + entity.kind;
+ iconElem.title = name + " " + entity.kind;
+ iconElem.href = toRoot + entity[entity.kind];
+ entityLi.appendChild(iconElem);
+
+ if (entity.kind != "object" && entity.object) {
+ var companion = document.createElement("a");
+ companion.className = "icon object";
+ companion.title = name + " companion object";
+ companion.href = toRoot + entity.object;
+ entityLi.insertBefore(companion, iconElem);
+ } else {
+ var spacer = document.createElement("div");
+ spacer.className = "icon spacer";
+ entityLi.insertBefore(spacer, iconElem);
+ }
- var index = 0;
+ var nameElem = document.createElement("span");
+ nameElem.className = "entity";
- var searchLoop = function () {
- var packages = Index.keys(Index.PACKAGES).sort();
+ var entityUrl = document.createElement("a");
+ entityUrl.title = name;
+ entityUrl.href = toRoot + entity[entity.kind];
+ entityUrl.appendChild(document.createTextNode(name));
- while (packages[index]) {
- var pack = packages[index];
- var children = Index.PACKAGES[pack];
- index++;
+ nameElem.appendChild(entityUrl);
+ entityLi.appendChild(nameElem);
- if (focusFilterState) {
- if (pack == focusFilterState ||
- pack.indexOf(focusFilterState + '.') == 0) {
- ;
- } else {
- continue;
- }
- }
+ var membersUl = document.createElement("ul");
+ membersUl.className = "members";
+ entityLi.appendChild(membersUl);
- var matched = $.grep(children, function (child, i) {
- return queryRegExp.test(child.name);
- });
- if (matched.length > 0) {
- $('#tpl').append(Index.createPackageTree(pack, matched,
- focusFilterState));
- scheduler.add('filter', searchLoop);
- return;
+ searchEntity(entity, membersUl, regExp)
+ .then(function(res) {
+ if (res.length > 0) {
+ packLink.style.display = "block";
+ entityUl.appendChild(entityLi);
}
- }
-
- $('#tpl a.packfocus').click(function () {
- focusFilter($(this).parent().parent());
- $("#tpl").addClass("packfocused");
});
- configureHideFilter();
- };
+ });
+}
- scheduler.add('filter', searchLoop);
+/** This function inserts `li` into the `ul` ordered by the li's id
+ *
+ * @param {Node} ul: the list in which to insert `li`
+ * @param {Node} li: item to insert
+ */
+function insertSorted(ul, li) {
+ var lis = ul.childNodes;
+ var beforeLi = null;
+
+ for (var i = 0; i < lis.length; i++) {
+ if (lis[i].id > li.id)
+ beforeLi = lis[i];
}
+
+ // if beforeLi == null, it will be inserted last
+ ul.insertBefore(li, beforeLi);
}
-/* Configures the hide tool by adding the hide link to all packages. */
-function configureHideFilter() {
- $('#tpl li.pack a.packhide').click(function () {
- var packhide = $(this)
- var action = packhide.text();
+/** Defines the callback when a package has been searched and searches its
+ * members
+ *
+ * It will search all entities which matched the regExp.
+ *
+ * @param {Object} res: this is the searched package. It will contain the map
+ * from the `searchPackage`function.
+ * @param {RegExp} regExp
+ */
+function handleSearchedPackage(res, regExp) {
+ $("div#search-results").show();
+ $("#search > span.close-results").show();
+ $("#search > span#doc-title").hide();
- var ol = $(this).parent().parent();
+ var searchRes = document.getElementById("results-content");
+ var entityDiv = document.getElementById("entity-results");
- if (action == "hide") {
- Index.hidePackage(ol);
- packhide.text("show");
- }
- else {
- Index.showPackage(ol, kindFilterState);
- packhide.text("hide");
- }
- return false;
- });
-}
+ var packLink = document.createElement("a");
+ packLink.className = "package";
+ packLink.title = res.package;
+ packLink.href = toRoot + urlFriendlyEntity(res.package).replace(new RegExp("\\.", "g"), "/") + "/index.html";
+ packLink.appendChild(document.createTextNode(res.package));
-/* Configures the focus tool by adding the focus bar in the filter box (initially hidden), and by adding the focus
- link to all packages. */
-function configureFocusFilter() {
- scheduler.add("init", function() {
- focusFilterState = null;
- if ($("#focusfilter").length == 0) {
- $("#filter").append("<div id='focusfilter'>focused on <span class='focuscoll'></span> <a class='focusremove'>✖</a></div>");
- $("#focusfilter > .focusremove").click(function(event) {
- textFilter();
-
- $("#focusfilter").hide();
- $("#kindfilter").show();
- $("#tpl").removeClass("packfocused");
- resizeFilterBlock();
- focusFilterState = null;
- });
- $("#focusfilter").hide();
- resizeFilterBlock();
- }
- });
- scheduler.add("init", function() {
- $('#tpl li.pack a.packfocus').click(function () {
- focusFilter($(this).parent());
- return false;
- });
- });
-}
+ if (res.matched.length == 0)
+ packLink.style.display = "none";
-/* Focuses the entity index on a specific package. To do so, it will copy the sub-templates and sub-packages of the
- focuses package into the top-level templates and packages position of the index. The original top-level
- @param package The <li> element that corresponds to the package in the entity index */
-function focusFilter(package) {
- scheduler.clear("filter");
+ entityDiv.appendChild(packLink);
- var currentFocus = $('li.pack > .tplshow', package).text();
- $("#focusfilter > .focuscoll").empty();
- $("#focusfilter > .focuscoll").append(currentFocus);
+ var ul = document.createElement("ul")
+ ul.className = "entities";
- $("#focusfilter").show();
- $("#kindfilter").hide();
- resizeFilterBlock();
- focusFilterState = currentFocus;
- kindFilterSync();
+ // Generate html list items from results
+ res.matched
+ .map(function(entity) { return listItem(entity, regExp); })
+ .forEach(function(li) { ul.appendChild(li); });
- textFilter();
+ entityDiv.appendChild(ul);
}
-function configureKindFilter() {
- scheduler.add("init", function() {
- kindFilterState = "all";
- $("#filter").append("<div id='kindfilter-container'><div id='kindfilter'><span>Fold All</span></div></div>");
-
- while(isNaN(scrollbarWidth())) {
- // wait until the width is available
- }
+/** Searches an entity asynchronously for regExp matches in an entity's members
+ *
+ * @param {Object} entity: the entity to be searched
+ * @param {Node} ul: the list in which to insert the list item created
+ * @param {RegExp} regExp
+ */
+function searchEntity(entity, ul, regExp) {
+ return new Promise(function(resolve, reject) {
+ var matchingMembers = $.grep(entity.members, function(member, i) {
+ return regExp.test(member.label);
+ });
- $("#kindfilter").css({"margin-right": (scrollbarWidth() + 7) + "px"});
- $("#kindfilter").unbind("click");
- $("#kindfilter").click(function(event) {
- $("#kindfilter").toggleClass("open");
- kindFilter("packs");
+ resolve(matchingMembers);
+ })
+ .then(function(res) {
+ res.forEach(function(elem) {
+ var kind = document.createElement("span");
+ kind.className = "kind";
+ kind.appendChild(document.createTextNode(elem.kind));
+
+ var label = document.createElement("a");
+ label.title = elem.label;
+ label.href = toRoot + elem.link;
+ label.className = "label";
+ label.appendChild(document.createTextNode(elem.label));
+
+ var tail = document.createElement("span");
+ tail.className = "tail";
+ tail.appendChild(document.createTextNode(elem.tail));
+
+ var li = document.createElement("li");
+ li.appendChild(kind);
+ li.appendChild(label);
+ li.appendChild(tail);
+
+ ul.appendChild(li);
});
- resizeFilterBlock();
+ return res;
});
}
-function kindFilter(kind) {
- if (kind == "packs") {
- kindFilterState = "packs";
- kindFilterSync();
- $("#kindfilter > span").replaceWith("<span>Unfold All</span>");
- $("#kindfilter").unbind("click");
- $("#kindfilter").click(function(event) {
- $("#kindfilter").toggleClass("open");
- kindFilter("all");
- });
- }
- else {
- kindFilterState = "all";
- kindFilterSync();
- $("#kindfilter > span").replaceWith("<span>Fold All</span>");
- $("#kindfilter").unbind("click");
- $("#kindfilter").click(function(event) {
- $("#kindfilter").toggleClass("open");
- kindFilter("packs");
- });
+/** Creates a list item representing an entity
+ *
+ * @param {Object} entity, the searched entity to be displayed
+ * @param {RegExp} regExp
+ * @return {Node} list item containing entity
+ */
+function listItem(entity, regExp) {
+ var name = entity.name.split('.').pop()
+ var nameElem = document.createElement("span");
+ nameElem.className = "entity";
+
+ var entityUrl = document.createElement("a");
+ entityUrl.title = name;
+ entityUrl.href = toRoot + entity[entity.kind];
+
+ entityUrl.appendChild(document.createTextNode(name));
+ nameElem.appendChild(entityUrl);
+
+ var iconElem = document.createElement("a");
+ iconElem.className = "icon " + entity.kind;
+ iconElem.title = name + " " + entity.kind;
+ iconElem.href = toRoot + entity[entity.kind];
+
+ var li = document.createElement("li");
+ li.id = entity.name.replace(new RegExp("\\.", "g"),"-");
+ li.appendChild(iconElem);
+ li.appendChild(nameElem);
+
+ if (entity.kind != "object" && entity.object) {
+ var companion = document.createElement("a");
+ companion.title = name + " companion object";
+ companion.href = toRoot + entity.object;
+ companion.className = "icon object";
+ li.insertBefore(companion, iconElem);
+ } else {
+ var spacer = document.createElement("div");
+ spacer.className = "icon spacer";
+ li.appendChild(spacer);
}
+
+ var ul = document.createElement("ul");
+ ul.className = "members";
+
+ li.appendChild(ul);
+
+ return li;
}
-/* Applies the kind filter. */
-function kindFilterSync() {
- if (kindFilterState == "all" || focusFilterState != null) {
- $("#tpl a.packhide").text('hide');
- $("#tpl ol.templates").show();
- } else {
- $("#tpl a.packhide").text('show');
- $("#tpl ol.templates").hide();
+/** Searches all packages and entities for the current search string in
+ * the input field "#textfilter"
+ *
+ * Then shows the results in div#search-results
+ */
+function searchAll() {
+ scheduler.clear("search"); // clear previous search
+ var searchStr = $("#textfilter input").attr("value").trim() || '';
+
+ if (searchStr === '') {
+ $("div#search-results").hide();
+ $("#search > span.close-results").hide();
+ $("#search > span#doc-title").show();
+ return;
}
+
+ $("div#results-content > span.search-text").remove();
+
+ var memberResults = document.getElementById("member-results");
+ memberResults.innerHTML = "";
+ var memberH1 = document.createElement("h1");
+ memberH1.className = "result-type";
+ memberH1.innerHTML = "Member results";
+ memberResults.appendChild(memberH1);
+
+ var entityResults = document.getElementById("entity-results");
+ entityResults.innerHTML = "";
+ var entityH1 = document.createElement("h1");
+ entityH1.className = "result-type";
+ entityH1.innerHTML = "Entity results";
+ entityResults.appendChild(entityH1);
+
+ $("div#results-content")
+ .prepend("<span class='search-text'>"
+ +" Showing results for <span class='query-str'>\"" + searchStr + "\"</span>"
+ +"</span>");
+
+ var regExp = compilePattern(searchStr);
+
+ // Search for all entities matching query
+ Index
+ .keys(Index.PACKAGES)
+ .sort()
+ .forEach(function(elem) { searchPackage(elem, regExp); })
}
-function resizeFilterBlock() {
- $("#tpl").css("top", $("#filter").outerHeight(true));
+/** Check if user agent is associated with a known mobile browser */
+function isMobile() {
+ return /Android|webOS|Mobi|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
-function scrollbarWidth() {
- return $("#tpl").width() - $("#tpl")[0].clientWidth;
+function urlFriendlyEntity(entity) {
+ var corr = {
+ '\\+': '$plus',
+ ':': '$colon'
+ };
+
+ for (k in corr)
+ entity = entity.replace(new RegExp(k, 'g'), corr[k]);
+
+ return entity;
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.eot b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.eot
new file mode 100644
index 0000000000..7437fd9805
--- /dev/null
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.eot
Binary files differ
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.ttf b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.ttf
new file mode 100644
index 0000000000..4e7128a481
--- /dev/null
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.ttf
Binary files differ
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.woff b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.woff
new file mode 100644
index 0000000000..48915bb476
--- /dev/null
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/lato-v11-latin-100.woff
Binary files differ
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/scheduler.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/scheduler.js
index 4417f5b438..39ce2a5d29 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/scheduler.js
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/scheduler.js
@@ -1,5 +1,5 @@
// © 2010 EPFL/LAMP
-// code by Gilles Dubochet
+// code by Gilles Dubochet, Felix Mulder
function Scheduler() {
var scheduler = this;
@@ -7,38 +7,44 @@ function Scheduler() {
this.timeout = undefined;
this.queues = new Array(0); // an array of work pacakges indexed by index in the labels table.
this.labels = new Array(0); // an indexed array of labels indexed by priority. This should be short.
+
this.label = function(name, priority) {
this.name = name;
this.priority = priority;
}
+
this.work = function(fn, self, args) {
this.fn = fn;
this.self = self;
this.args = args;
}
+
this.addLabel = function(name, priority) {
var idx = 0;
while (idx < scheduler.queues.length && scheduler.labels[idx].priority <= priority) { idx = idx + 1; }
scheduler.labels.splice(idx, 0, new scheduler.label(name, priority));
scheduler.queues.splice(idx, 0, new Array(0));
}
+
this.clearLabel = function(name) {
- var idx = 0;
- while (idx < scheduler.queues.length && scheduler.labels[idx].name != name) { idx = idx + 1; }
- if (idx < scheduler.queues.length && scheduler.labels[i].name == name) {
+ var idx = scheduler.indexOf(name);
+ if (idx != -1) {
scheduler.labels.splice(idx, 1);
scheduler.queues.splice(idx, 1);
}
}
+
this.nextWork = function() {
var fn = undefined;
var idx = 0;
while (idx < scheduler.queues.length && scheduler.queues[idx].length == 0) { idx = idx + 1; }
- if (idx < scheduler.queues.length && scheduler.queues[idx].length > 0) {
+
+ if (idx < scheduler.queues.length && scheduler.queues[idx].length > 0)
var fn = scheduler.queues[idx].shift();
- }
+
return fn;
}
+
this.add = function(labelName, fn, self, args) {
var doWork = function() {
scheduler.timeout = setTimeout(function() {
@@ -53,19 +59,43 @@ function Scheduler() {
}
}, resolution);
}
- var idx = 0;
- while (idx < scheduler.labels.length && scheduler.labels[idx].name != labelName) { idx = idx + 1; }
- if (idx < scheduler.queues.length && scheduler.labels[idx].name == labelName) {
+
+ var idx = scheduler.indexOf(labelName)
+ if (idx != -1) {
scheduler.queues[idx].push(new scheduler.work(fn, self, args));
if (scheduler.timeout == undefined) doWork();
+ } else {
+ throw("queue for add is non existant");
}
- else throw("queue for add is non existant");
}
+
this.clear = function(labelName) {
+ scheduler.queues[scheduler.indexOf(labelName)] = new Array();
+ }
+
+ this.indexOf = function(label) {
var idx = 0;
- while (idx < scheduler.labels.length && scheduler.labels[idx].name != labelName) { idx = idx + 1; }
- if (idx < scheduler.queues.length && scheduler.labels[idx].name == labelName) {
- scheduler.queues[idx] = new Array();
+ while (idx < scheduler.labels.length && scheduler.labels[idx].name != label)
+ idx++;
+
+ return idx < scheduler.queues.length && scheduler.labels[idx].name == label ? idx : -1;
+ }
+
+ this.queueEmpty = function(label) {
+ var idx = scheduler.indexOf(label);
+ if (idx != -1)
+ return scheduler.queues[idx].length == 0;
+ else
+ throw("queue for label '" + label + "' is non existant");
+ }
+
+ this.scheduleLast = function(label, fn) {
+ if (scheduler.queueEmpty(label)) {
+ fn();
+ } else {
+ scheduler.add(label, function() {
+ scheduler.scheduleLast(label, fn);
+ });
}
}
};
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css
index 43e59076ca..a91e442621 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css
@@ -29,39 +29,6 @@ a img { border: none; }
input { border-width: 0px; }
-/* Fonts */
-@font-face {
- font-family: 'Source Code Pro';
- font-style: normal;
- font-weight: 400;
- src: url('source-code-pro-v6-latin-regular.eot');
- src: local('Source Code Pro'), local('SourceCodePro-Regular'),
- url('source-code-pro-v6-latin-regular.eot?#iefix') format('embedded-opentype'),
- url('source-code-pro-v6-latin-regular.woff') format('woff'),
- url('source-code-pro-v6-latin-regular.ttf') format('truetype');
-}
-@font-face {
- font-family: 'Source Code Pro';
- font-style: normal;
- font-weight: 700;
- src: url('source-code-pro-v6-latin-700.eot');
- src: local('Source Code Pro Bold'), local('SourceCodePro-Bold'),
- url('source-code-pro-v6-latin-700.eot?#iefix') format('embedded-opentype'),
- url('source-code-pro-v6-latin-700.woff') format('woff'),
- url('source-code-pro-v6-latin-700.ttf') format('truetype');
-}
-
-@font-face {
- font-family: 'Open Sans';
- font-style: normal;
- font-weight: 400;
- src: url('open-sans-v13-latin-regular.eot');
- src: local('Open Sans'), local('OpenSans'),
- url('open-sans-v13-latin-regular.eot?#iefix') format('embedded-opentype'),
- url('open-sans-v13-latin-regular.woff') format('woff'),
- url('open-sans-v13-latin-regular.ttf') format('truetype');
-}
-
/* Page */
body {
overflow-x: hidden;
@@ -69,32 +36,24 @@ body {
background-color: #f0f3f6;
}
-html {
- box-sizing: border-box;
-}
-
-*, *:before, *:after {
- box-sizing: inherit;
-}
-
#footer {
text-align: center;
color: #858484;
bottom: 0;
- width: 100%;
height: 20px;
+ margin: 0 1em 0.5em;
}
-a[href] {
+#content-container a[href] {
text-decoration: underline;
color: #315479;
}
-a[href]:hover {
+#content-container a[href]:hover {
text-decoration: none;
}
-body.trait > div#definition {
+body.trait div#definition {
background-color: #2e6d82;
}
@@ -107,10 +66,13 @@ body.trait > div#definition {
}
#definition {
+ position: relative;
display: block;
- padding: 5px 0px;
- height: 5.5em;
+ padding: 5px 0;
padding: 0;
+ margin: 0.5em;
+ border-radius: 0.2em;
+ box-shadow: 0 0 10px rgba(0,0,0,0.2);
}
#definition > a > img {
@@ -132,8 +94,8 @@ body.trait > div#definition {
}
#definition h1 > a {
- color: #fff;
- text-decoration: none;
+ color: #fff !important;
+ text-decoration: none !important;
}
#definition #owner {
@@ -156,13 +118,10 @@ body.trait > div#definition {
min-height: 18px;
font-size: 0.9em;
padding: 8px;
- box-shadow: 0 0 0.35em 0.05em rgba(0,0,0,0.5);
- position: fixed;
- top: 6.1em;
- left: 0;
width: 100%;
- z-index: 9998;
color: #103a51;
+ border-bottom-left-radius: 0.2em;
+ border-bottom-right-radius: 0.2em;
}
#signature > span.modifier_kind {
@@ -171,6 +130,7 @@ body.trait > div#definition {
text-align: left;
width: auto;
position: static;
+ padding-left: 0;
}
#signature > span.symbol {
@@ -219,21 +179,10 @@ body.trait > div#definition {
.value #definition {
background-color: #103A51; /* blue */
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- z-index: 9999;
}
.type #definition {
background-color: rgba(49, 101, 85, 1); /* green */
- position: fixed;
- top: 0;
- left: 0;
- min-height: 5.5em;
- width: 100%;
- z-index: 9999;
}
.abstract.type #definition {
@@ -285,12 +234,13 @@ body.abstract.type div.big-circle {
}
#template {
- margin: 0.9em 0.75em 2em 0.75em;
+ margin: 0.9em 0.75em 0.75em;
border-radius: 0.2em;
background-color: #fff;
-webkit-box-shadow: 0 0 10px rgba(0,0,0,0.1);
box-shadow: 0 0 10px rgba(0,0,0,0.1);
padding-bottom: 0.5em;
+ overflow: hidden;
}
#order {
@@ -369,19 +319,20 @@ dl.attributes > dd {
/* Member cells */
div.members > ol {
background-color: white;
- list-style: none
+ list-style: none;
+ padding: 0 10px;
}
div.members > ol > li {
- display: block;
- padding: 5px 0 6px;
- margin: 0 10px;
+ display: table;
+ width: 100%;
position: relative;
background-color: #e1e7ed;
border-radius: 0.2em;
color: #103a51;
padding: 5px 0 5px;
margin-bottom: 0.4em;
+ min-height: 2.8em;
}
div.members > ol >li.selected,
@@ -413,17 +364,25 @@ div.members > ol > li:last-child {
display: block;
}
-.signature .modifier_kind {
- position: absolute;
+.modifier_kind {
+ font-family: "Source Code Pro";
+ font-size: 0.8rem;
+ padding-right: 0.5em;
text-align: right;
- width: 14em;
+ display: table-cell;
+ white-space: nowrap;
+ width: 16em;
}
-.signature > a > .symbol > .name {
+.symbol {
+ font-family: "Source Code Pro";
+}
+
+a > .symbol > .name {
text-decoration: underline;
}
-.signature > a:hover > .symbol > .name {
+a:hover > .symbol > .name {
text-decoration: none;
}
@@ -432,8 +391,7 @@ div.members > ol > li:last-child {
}
.signature > .symbol {
- display: block;
- padding-left: 14.7em;
+ display: inline;
}
.signature .name {
@@ -441,62 +399,68 @@ div.members > ol > li:last-child {
font-weight: bold;
}
-.signature .symbol > .implicit {
+span.symbol > span.name {
+ font-weight: bold;
+}
+
+.symbol > .implicit {
display: inline-block;
font-weight: bold;
text-decoration: underline;
color: darkgreen;
}
-.signature .symbol .shadowed {
+.symbol .shadowed {
color: darkseagreen;
}
-.signature .symbol .params > .implicit {
+.symbol .params > .implicit {
font-style: italic;
}
-.signature .symbol .deprecated {
+.symbol .deprecated {
text-decoration: line-through;
}
-.signature .symbol .params .default {
+.symbol .params .default {
font-style: italic;
}
-#template .signature.closed {
+#template .closed {
cursor: pointer;
}
-#template .signature.closed:before {
+#template .closed:before {
content: "▶";
position: absolute;
left: 1em;
- top: 0.5em;
+ top: 0.35em;
}
-#template .signature.opened {
+#template .opened {
cursor: pointer;
}
-#template .signature.opened:before {
+#template .opened:before {
content: "▼";
position: absolute;
left: 1em;
- top: 0.5em;
+ top: 0.35em;
color: #2C475C;
}
-#template .values .signature .name {
+#template .values .name {
+ font-weight: 600;
color: darkblue;
}
-#template .types .signature .name {
+#template .types .name {
+ font-weight: 600;
color: darkgreen;
}
.full-signature-usecase h4 span {
- font-size: 0.9em;
+ font-size: 0.8rem;
}
.full-signature-usecase > #signature {
@@ -505,19 +469,19 @@ div.members > ol > li:last-child {
top: 0;
}
-.full-signature-usecase > .signature.closed:before {
+.full-signature-usecase > .signature > .closed:before {
content: "" !important;
}
-.full-signature-usecase > .signature.opened:before {
+.full-signature-usecase > .signature > .opened:before {
content: "" !important;
}
-#template .full-signature-usecase > .signature.closed {
+#template .full-signature-usecase > .signature > .closed {
background: none;
}
-#template .full-signature-usecase > .signature.opened {
+#template .full-signature-usecase > .signature > .opened {
background: none;
}
@@ -531,8 +495,8 @@ div.members > ol > li:last-child {
#definition .morelinks {
text-align: right;
position: absolute;
- top: 40px;
- right: 10px;
+ top: 2.95em;
+ right: 1em;
width: 450px;
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
}
@@ -725,11 +689,11 @@ div.fullcomment {
#template div.fullcommenttop,
#template div.fullcomment {
display:none;
- margin: 5px 0 0 14.7em;
+ margin: 0.5em 1em 0 0;
}
#template .shortcomment {
- margin: 5px 0 0 14.7em;
+ margin: 5px 0 0 0;
padding: 0;
font-family: "Open Sans";
}
@@ -739,7 +703,6 @@ div.fullcomment .block {
border-top: 2px solid #fff;
margin-top: 5px;
overflow: hidden;
- margin-right: 0.5em;
font-family: "Open Sans";
}
@@ -818,7 +781,7 @@ div.fullcomment dl.paramcmts > dd {
/* Members filter tool */
-#textfilter {
+#memberfilter {
position: relative;
display: block;
height: 2.7em;
@@ -826,7 +789,7 @@ div.fullcomment dl.paramcmts > dd {
margin-left: 1.5em;
}
-#textfilter > .input {
+#memberfilter > .input {
display: block;
position: absolute;
top: 0;
@@ -835,7 +798,7 @@ div.fullcomment dl.paramcmts > dd {
transition: 0.2s;
}
-#textfilter > .input > input {
+#memberfilter > .input > input {
color: #fff;
width: 100%;
border-radius: 0.2em;
@@ -844,7 +807,7 @@ div.fullcomment dl.paramcmts > dd {
font-family: "Open Sans";
}
-#textfilter > .clear {
+#memberfilter > .clear {
display: none;
position: absolute;
top: 0.6em;
@@ -854,7 +817,7 @@ div.fullcomment dl.paramcmts > dd {
color: rgba(255, 255, 255, 0.4);
}
-#textfilter > .clear:hover {
+#memberfilter > .clear:hover {
color: #fff;
cursor: pointer;
}
@@ -893,7 +856,7 @@ div.fullcomment dl.paramcmts > dd {
opacity: 1;
}
-#mbrsel:hover #textfilter > .input {
+#mbrsel:hover #memberfilter > .input {
left: 0.7em;
}
@@ -1072,24 +1035,16 @@ and (-webkit-device-pixel-ratio: 2)
min-width: 300px;
}
- .signature .modifier_kind {
- width: 10em;
+ #template .modifier_kind {
+ width: 1px;
+ padding-left: 2.5em;
}
- .signature > .symbol {
- padding-left: 10.7em;
- }
-
- #template .shortcomment {
- margin-left: 10.7em;
- }
-
- #template div.fullcommenttop, #template div.fullcomment {
- margin-left: 10.7em;
+ span.modifier_kind > span.modifier {
+ display: none;
}
#definition {
- min-width: 300px;
height: 6em;
}
@@ -1125,16 +1080,8 @@ only screen /* iPhone 6 */
and (max-device-width: 667px)
and (-webkit-device-pixel-ratio: 2)
{
- #definition {
- position: absolute !important;
- min-height: 0 !important;
- height: 4em !important;
- }
-
#signature {
- position: absolute !important;
font-size: 0.7em;
- top: 5.7em;
}
#definition > h1 {
@@ -1149,12 +1096,8 @@ and (-webkit-device-pixel-ratio: 2)
padding-top: 0.7em;
}
- div.fullcommenttop {
- margin-top: 11.6em;
- }
-
- #template .shortcomment {
- margin-left: 1em;
+ #signature > span.modifier_kind {
+ width: auto;
}
div.fullcomment dl.attributes > dt {
@@ -1167,10 +1110,6 @@ and (-webkit-device-pixel-ratio: 2)
clear: both;
}
- #template div.fullcommenttop, #template div.fullcomment {
- margin-left: 1em;
- }
-
.big-circle {
width: 3em;
height: 3em;
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js
index 3baf0d9db7..50804c029f 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js
@@ -17,38 +17,16 @@ $(document).ready(function() {
});
$("#template > div > div > ol > li > span > a").click(function(e) {
- $("#template > div > div > ol > li").removeClass("selected");
- $(this).parent().parent().addClass("selected");
- var defHeight = $("#definition").height() + $("#signature").height() + 50;
- $('html,body').animate({scrollTop: $(this).offset().top - defHeight}, 500);
- });
-
- /* Handle dynamic size of signature and offset the fullcommenttop div
- * appropriately
- *
- * Some mobile devices render quite slowly, delay the margin-top
- * calculation if mobile
- */
- if(/Android|webOS|Mobi|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
- setTimeout(function() {
- $("div.fullcommenttop").css({
- "margin-top": $("#definition").height() + $("#signature").height() + 15
- });
- }, 1000);
- } else {
- $("div.fullcommenttop").css({
- "margin-top": $("#definition").height() + $("#signature").height() + 15
- });
- }
-
- /* When the window is resized, adjust the fullcommenttop div's offset */
- $(window).resize(function() {
- $("div.fullcommenttop").css({
- "margin-top": $("#definition").height() + $("#signature").height() + 15
- });
+ var href = $(this).attr("href");
+ if (href.indexOf("#") != -1) {
+ e.preventDefault();
+ location.hash = href.split("#").pop();
+ $("#template > div > div > ol > li").removeClass("selected");
+ var parent = $(this).parent().parent().addClass("selected");
+ $("#content-container").animate({scrollTop: $("#content-container").scrollTop() + $(this).offset().top - $("#search").height() - 22}, 500);
+ }
});
-
var controls = {
visibility: {
publicOnly: $("#visbl").find("> ol > li.public"),
@@ -93,10 +71,8 @@ $(document).ready(function() {
}
filter();
- window.scrollTo(0, 0);
- var defHeight = $("#definition").height() + $("#signature").height() + 50;
jqElemParent.addClass("selected");
- $('html,body').animate({scrollTop: jqElemParent.offset().top - defHeight}, 1000);
+ $("#content-container").animate({scrollTop: jqElemParent.offset().top - $("#search").height() - 5 }, 1000);
}
var isHiddenClass = function (name) {
@@ -124,7 +100,7 @@ $(document).ready(function() {
filter();
// Member filter box
- var input = $("#textfilter input");
+ var input = $("#memberfilter input");
input.bind("keyup", function(event) {
switch ( event.keyCode ) {
@@ -161,8 +137,8 @@ $(document).ready(function() {
input.focus(function(event) {
input.select();
});
- $("#textfilter > .clear").click(function() {
- $("#textfilter input").attr("value", "");
+ $("#memberfilter > .clear").click(function() {
+ $("#memberfilter input").attr("value", "");
filter();
});
$(document).keydown(function(event) {
@@ -262,7 +238,7 @@ $(document).ready(function() {
/* Add toggle arrows */
//var docAllSigs = $("#template li").has(".fullcomment").find(".signature");
// trying to speed things up a little bit
- var docAllSigs = $("#template li[fullComment=yes] .signature");
+ var docAllSigs = $("#template li[fullComment=yes] .modifier_kind");
function commentToggleFct(signature){
var parent = signature.parent();
@@ -271,12 +247,22 @@ $(document).ready(function() {
var vis = $(":visible", fullComment);
signature.toggleClass("closed").toggleClass("opened");
if (vis.length > 0) {
- shortComment.slideDown(100);
- fullComment.slideUp(100);
+ if (!isMobile()) {
+ shortComment.slideDown(100);
+ fullComment.slideUp(100);
+ } else {
+ fullComment.hide();
+ shortComment.show();
+ }
}
else {
- shortComment.slideUp(100);
- fullComment.slideDown(100);
+ if (!isMobile()) {
+ shortComment.slideUp(100);
+ fullComment.slideDown(100);
+ } else {
+ shortComment.hide();
+ fullComment.show();
+ }
}
};
docAllSigs.addClass("closed");
@@ -288,7 +274,13 @@ $(document).ready(function() {
function toggleShowContentFct(e){
e.toggleClass("open");
var content = $(".hiddenContent", e.parent().get(0));
- (content.is(':visible') ? content.slideUp : content.slideDown)(100);
+ if(content.is(':visible')) {
+ if (!isMobile()) content.slideUp(100);
+ else content.hide();
+ } else {
+ if (!isMobile()) content.slideDown(100);
+ else content.show();
+ }
};
$(".toggle:not(.diagram-link)").click(function() {
@@ -315,11 +307,11 @@ $(document).ready(function() {
}
$("#mbrsel-input").on("focus", function() {
- $("#textfilter > .clear").show();
+ $("#memberfilter > .clear").show();
});
$("#mbrsel-input").on("blur", function() {
- $("#textfilter > .clear").hide();
+ $("#memberfilter > .clear").hide();
});
});
@@ -447,7 +439,7 @@ function initInherit() {
/* filter used to take boolean scrollToMember */
function filter() {
- var query = $.trim($("#textfilter input").val()).toLowerCase();
+ var query = $.trim($("#memberfilter input").val()).toLowerCase();
query = query.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&").replace(/\s+/g, "|");
var queryRegExp = new RegExp(query, "i");
var privateMembersHidden = $("#visbl > ol > li.public").hasClass("in");
@@ -534,21 +526,24 @@ function filter() {
});
if (membersVisible)
- members.show();
+ members.show();
else
- members.hide();
+ members.hide();
};
return false;
};
-function windowTitle()
-{
+function windowTitle() {
try {
parent.document.title=document.title;
- }
- catch(e) {
+ } catch(e) {
// Chrome doesn't allow settings the parent's title when
// used on the local file system.
}
};
+
+/** Check if user agent is associated with a known mobile browser */
+function isMobile() {
+ return /Android|webOS|Mobi|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
+}