aboutsummaryrefslogtreecommitdiff
path: root/dottydoc/js/src/Search.scala
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-06-01 17:23:37 +0200
committerFelix Mulder <felix.mulder@gmail.com>2016-08-19 15:37:25 +0200
commita099344f81ddb0463bbc6da99c376df9f70667df (patch)
tree73bbb72d67086db7d6c5eadda6fbf3a7122f763e /dottydoc/js/src/Search.scala
parent756861ed32207b5e1ab7964bcfdbe4165b68723e (diff)
downloaddotty-a099344f81ddb0463bbc6da99c376df9f70667df.tar.gz
dotty-a099344f81ddb0463bbc6da99c376df9f70667df.tar.bz2
dotty-a099344f81ddb0463bbc6da99c376df9f70667df.zip
Add basic implementation of toplevel entity search
Diffstat (limited to 'dottydoc/js/src/Search.scala')
-rw-r--r--dottydoc/js/src/Search.scala115
1 files changed, 101 insertions, 14 deletions
diff --git a/dottydoc/js/src/Search.scala b/dottydoc/js/src/Search.scala
index 0683c5d95..6625e3c78 100644
--- a/dottydoc/js/src/Search.scala
+++ b/dottydoc/js/src/Search.scala
@@ -2,33 +2,120 @@ package dotty.tools.dottydoc
package js
import scala.scalajs.{ js => sjs }
-import sjs.timers._
-import org.scalajs.dom
+import sjs.timers.setTimeout
+import scalatags.JsDom.all._
+import org.scalajs.dom.html.{ Input, Div }
+import org.scalajs.dom.{ document, Event }
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.concurrent.Future
-object Search {
+import js.model._
+import js.model.ops._
+
+class Search(val input: Input) {
private var isSearching = false
- def apply(input: dom.html.Input) = considerSearch(input)
+ private val mainDiv = document
+ .getElementById("entity-container")
+ .asInstanceOf[Div]
+ private val resultsDiv = document
+ .getElementById("search-results")
+ .asInstanceOf[Div]
+
+ /** Search result ADTs */
+ private case class PackageResults(matching: Stream[Package], nonMatching: Stream[Package])
+ private object PackageResults {
+ def empty = PackageResults(Stream.empty, Stream.empty)
+ }
- def considerSearch(input: dom.html.Input): dom.Event => Unit = { e =>
- val query = input.value
+ /** Entry point into search, will consider whether to start searching or not,
+ * then call `performSearch`
+ */
+ def search(): Event => Unit = { e =>
+ val query = input.value.trim
if (query.length > 2) setTimeout(200) {
if (!isSearching) {
isSearching = true
- performSearch(query)
+ performSearch(query.toLowerCase).map { _ => isSearching = false }
}
}
+ else if (query.length == 0)
+ hideSearchDiv()
}
- def performSearch(query: String): Unit = {
- println(s"searching for $query...")
+ private def performSearch(query: String): Future[Unit] =
+ for (PackageResults(matching, nonMatching) <- searchPackages(query)) yield {
+ // Clear old results, add new result categories add close button
+ resultsDiv.innerHTML = ""
+ val toplevelRes = div(id := "toplevel-results").render
+ val methodRes = div(id := "method-results").render
+ val closeButton = button(
+ id := "close-button",
+ onclick := { _: Event =>
+ resetInput()
+ hideSearchDiv()
+ },
+ cls := "mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored",
+ i(cls := "material-icons", "clear")
+ ).render
+
+ resultsDiv.appendChild(toplevelRes)
+ resultsDiv.appendChild(methodRes)
+ resultsDiv.appendChild(closeButton)
+
+ // Add all matching toplevel entities
+ matching
+ .toStream
+ .sortBy(_.name)
+ .map(createPackageCard)
+ .foreach(toplevelRes.appendChild)
+
+ // Hide entity and show results instead
+ showSearchDiv()
+ }
+
+ private def searchPackages(query: String): Future[PackageResults] = Future {
+ EntityIndex.packages.values.foldLeft(PackageResults.empty) { (acc, p) =>
+ val matchingMembers = p.members.collect {
+ case x if (x.name.toLowerCase.contains(query) && x.kind != "package") => x
+ }
+
+ println("We found all matching members maybe")
+ sjs.Dynamic.global.console.log(p)
- val matchingPackages = EntityIndex.packages.values.collect {
- case x if x.name.startsWith(query) => x
+ if (p.name.toLowerCase.contains(query) || matchingMembers.nonEmpty)
+ acc.copy(matching = p.withMembers(matchingMembers) #:: acc.matching)
+ else acc
}
+ }
+
+ private def createPackageCard(pack: Package): Div = div(
+ cls := "mdl-card mdl-shadow--2dp package-result",
+ div(cls := "mdl-card__title", h2(cls := "mdl-card__title-text", pack.name)),
+ ul(pack.members.map(createEntityLi).toList)
+ ).render
+
+ private def createEntityLi(e: Entity) = li(
+ a(
+ href := toRoot + e.path.mkString("", "/", ".html"),
+ e.kind + " " + e.name
+ )
+ )
+
+ private def toRoot = "../" * (EntityIndex.currentEntity.path.length - 1)
+
+ private def resetInput() = {
+ input.value = ""
+ input.parentElement.className = input.parentElement.className.replaceAll("is-dirty", "")
+ }
+
+ private def showSearchDiv() = {
+ mainDiv.style.display = "none"
+ resultsDiv.style.display = "block"
+ }
- println("Found matching packages: ")
- matchingPackages.map(_.name).foreach(println)
- isSearching = false
+ private def hideSearchDiv() = {
+ resultsDiv.style.display = "none"
+ mainDiv.style.display = "block"
}
}