|
| 1 | +package dotty.dokka |
| 2 | + |
| 3 | +import org.scalajs.dom._ |
| 4 | +import org.scalajs.dom.html.Input |
| 5 | + |
| 6 | +class SearchbarComponent(val callback: (String) => List[PageEntry]): |
| 7 | + val resultsChunkSize = 100 |
| 8 | + extension (p: PageEntry) |
| 9 | + def toHTML = |
| 10 | + val wrapper = document.createElement("div").asInstanceOf[html.Div] |
| 11 | + wrapper.classList.add("scala3doc-searchbar-result") |
| 12 | + wrapper.classList.add("monospace") |
| 13 | + |
| 14 | + val resultA = document.createElement("a").asInstanceOf[html.Anchor] |
| 15 | + resultA.href = Globals.pathToRoot + p.location |
| 16 | + resultA.text = s"${p.fullName}" |
| 17 | + |
| 18 | + val location = document.createElement("span") |
| 19 | + location.classList.add("pull-right") |
| 20 | + location.classList.add("scala3doc-searchbar-location") |
| 21 | + location.textContent = p.description |
| 22 | + |
| 23 | + wrapper.appendChild(resultA) |
| 24 | + wrapper.appendChild(location) |
| 25 | + wrapper |
| 26 | + |
| 27 | + def handleNewQuery(query: String) = |
| 28 | + val result = callback(query).map(_.toHTML) |
| 29 | + resultsDiv.scrollTop = 0 |
| 30 | + while (resultsDiv.hasChildNodes()) resultsDiv.removeChild(resultsDiv.lastChild) |
| 31 | + val fragment = document.createDocumentFragment() |
| 32 | + result.take(resultsChunkSize).foreach(fragment.appendChild) |
| 33 | + resultsDiv.appendChild(fragment) |
| 34 | + def loadMoreResults(result: List[raw.HTMLElement]): Unit = { |
| 35 | + resultsDiv.onscroll = (event: Event) => { |
| 36 | + if (resultsDiv.scrollHeight - resultsDiv.scrollTop == resultsDiv.clientHeight) |
| 37 | + { |
| 38 | + val fragment = document.createDocumentFragment() |
| 39 | + result.take(resultsChunkSize).foreach(fragment.appendChild) |
| 40 | + resultsDiv.appendChild(fragment) |
| 41 | + loadMoreResults(result.drop(resultsChunkSize)) |
| 42 | + } |
| 43 | + } |
| 44 | + } |
| 45 | + loadMoreResults(result.drop(resultsChunkSize)) |
| 46 | + |
| 47 | + private val searchIcon: html.Div = |
| 48 | + val span = document.createElement("span").asInstanceOf[html.Span] |
| 49 | + span.innerHTML = """<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"><path d="M19.64 18.36l-6.24-6.24a7.52 7.52 0 10-1.28 1.28l6.24 6.24zM7.5 13.4a5.9 5.9 0 115.9-5.9 5.91 5.91 0 01-5.9 5.9z"></path></svg>""" |
| 50 | + span.id = "scala3doc-search" |
| 51 | + span.onclick = (event: Event) => |
| 52 | + if (document.body.contains(rootDiv)) { |
| 53 | + document.body.removeChild(rootDiv) |
| 54 | + } |
| 55 | + else document.body.appendChild(rootDiv) |
| 56 | + |
| 57 | + val element = createNestingDiv("search-content")( |
| 58 | + createNestingDiv("search-container")( |
| 59 | + createNestingDiv("search")( |
| 60 | + span |
| 61 | + ) |
| 62 | + ) |
| 63 | + ) |
| 64 | + document.getElementById("scala3doc-searchBar").appendChild(element) |
| 65 | + element |
| 66 | + |
| 67 | + |
| 68 | + private val input: html.Input = |
| 69 | + val element = document.createElement("input").asInstanceOf[html.Input] |
| 70 | + element.id = "scala3doc-searchbar-input" |
| 71 | + element.addEventListener("input", (e) => handleNewQuery(e.target.asInstanceOf[html.Input].value)) |
| 72 | + element |
| 73 | + |
| 74 | + private val resultsDiv: html.Div = |
| 75 | + val element = document.createElement("div").asInstanceOf[html.Div] |
| 76 | + element.id = "scala3doc-searchbar-results" |
| 77 | + element |
| 78 | + |
| 79 | + private val rootHiddenClasses = "hidden" |
| 80 | + private val rootShowClasses = "" |
| 81 | + |
| 82 | + private def createNestingDiv(className: String)(innerElement: html.Element): html.Div = |
| 83 | + val element = document.createElement("div").asInstanceOf[html.Div] |
| 84 | + element.className = className |
| 85 | + element.appendChild(innerElement) |
| 86 | + element |
| 87 | + |
| 88 | + private val rootDiv: html.Div = |
| 89 | + val element = document.createElement("div").asInstanceOf[html.Div] |
| 90 | + element.addEventListener("mousedown", (e: Event) => e.stopPropagation()) |
| 91 | + searchIcon.addEventListener("mousedown", (e: Event) => e.stopPropagation()) |
| 92 | + document.body.addEventListener("mousedown", (e: Event) => |
| 93 | + if (document.body.contains(element)) { |
| 94 | + document.body.removeChild(element) |
| 95 | + } |
| 96 | + ) |
| 97 | + element.id = "scala3doc-searchbar" |
| 98 | + element.appendChild(input) |
| 99 | + element.appendChild(resultsDiv) |
| 100 | + element |
| 101 | + |
| 102 | + handleNewQuery("") |
0 commit comments