Skip to content

Commit 89a6409

Browse files
committed
Improvements to search UX
Pressing "S" while not focused on an input/textarea will now open the search. Pressing "F" while not focused on an input/textarea will focus the member filter input. Pressing Escape while focused on the search/filter will clear the input and close/unfocus it Search result links are now treated as block elements so you can click anywhere inside the rectangle rather than specifically on the result text.
1 parent 89e57aa commit 89a6409

File tree

4 files changed

+58
-2
lines changed

4 files changed

+58
-2
lines changed

scaladoc-js/resources/scaladoc-searchbar.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@
8888

8989
.scaladoc-searchbar-result a {
9090
color: #1f2326;
91+
/* for some reason, with display:block if there's a wrap between the
92+
* search result text and the location span, the dead space to the
93+
* left of the location span doesn't get treated as part of the block,
94+
* which defeats the purpose of making the <a> a block element.
95+
* But inline-block with width:100% works as desired.
96+
*/
97+
display: inline-block;
98+
width: 100%;
9199
}
92100

93101
.scaladoc-searchbar-result .scaladoc-searchbar-location {

scaladoc-js/src/searchbar/SearchbarComponent.scala

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
2121
location.textContent = p.description
2222

2323
wrapper.appendChild(resultA)
24-
wrapper.appendChild(location)
24+
resultA.appendChild(location)
2525
wrapper.addEventListener("mouseover", {
2626
case e: MouseEvent => handleHover(wrapper)
2727
})
@@ -59,6 +59,8 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
5959
document.body.appendChild(rootDiv)
6060
input.focus()
6161
}
62+
// open the search if the user hits the `s` key when not focused on a text input
63+
document.body.addEventListener("keydown", (e: KeyboardEvent) => handleGlobalKeyDown(e))
6264

6365
val element = createNestingDiv("search-content")(
6466
createNestingDiv("search-container")(
@@ -70,7 +72,6 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
7072
document.getElementById("scaladoc-searchBar").appendChild(element)
7173
element
7274

73-
7475
private val input: html.Input =
7576
val element = document.createElement("input").asInstanceOf[html.Input]
7677
element.id = "scaladoc-searchbar-input"
@@ -106,6 +107,7 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
106107
if e.keyCode == 40 then handleArrowDown()
107108
else if e.keyCode == 38 then handleArrowUp()
108109
else if e.keyCode == 13 then handleEnter()
110+
else if e.keyCode == 27 then handleEscape()
109111
})
110112
element.id = "scaladoc-searchbar"
111113
element.appendChild(input)
@@ -146,6 +148,12 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
146148
selectedElement.click()
147149
}
148150
}
151+
private def handleEscape() = {
152+
// clear the search input and close the search
153+
input.value = ""
154+
handleNewQuery("")
155+
document.body.removeChild(rootDiv)
156+
}
149157

150158
private def handleHover(elem: html.Element) = {
151159
val selectedElement = resultsDiv.querySelector("[selected]")
@@ -155,4 +163,18 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
155163
elem.setAttribute("selected","")
156164
}
157165

166+
private def handleGlobalKeyDown(e: KeyboardEvent) = {
167+
// if the user presses the "S" key while not focused on an input, open the search
168+
if (e.key == "s") {
169+
val tag = e.target.asInstanceOf[html.Element].tagName
170+
if (tag != "INPUT" && tag != "TEXTAREA") {
171+
if (!document.body.contains(rootDiv)) {
172+
document.body.appendChild(rootDiv)
173+
// if we focus during the event handler, the `s` gets typed into the input
174+
window.setTimeout(() => input.focus(), 1.0)
175+
}
176+
}
177+
}
178+
}
179+
158180
handleNewQuery("")

scaladoc/resources/dotty_res/scripts/components/Input.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,27 @@ class Input extends Component {
44

55
this.inputRef = findRef(".filterableInput");
66
this.onChangeFn = withEvent(this.inputRef, "input", this.onInputChange);
7+
this.onKeydownFn = withEvent(this.inputRef, "keydown", this.onKeydown);
78
}
89

910
onInputChange = ({ currentTarget: { value } }) => {
1011
this.props.onInputChange(value);
1112
};
1213

14+
onKeydown = (e) => {
15+
// if the user hits Escape while typing in the filter input,
16+
// clear the filter and un-focus the input
17+
if (e.keyCode == 27) {
18+
this.inputRef.value = '';
19+
this.onInputChange(e);
20+
setTimeout(() => this.inputRef.blur(), 1);
21+
}
22+
}
23+
1324
componentWillUnmount() {
1425
if (this.onChangeFn) {
1526
this.onChangeFn();
27+
this.onKeydownFn();
1628
}
1729
}
1830
}

scaladoc/resources/dotty_res/scripts/ux.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@ window.addEventListener("DOMContentLoaded", () => {
5454
hljs.registerLanguage("scala", highlightDotty);
5555
hljs.registerAliases(["dotty", "scala3"], "scala");
5656
hljs.initHighlighting();
57+
58+
/* listen for the `F` key to be pressed, to focus on the member filter input (if it's present) */
59+
document.body.addEventListener('keydown', e => {
60+
if (e.key == "f") {
61+
const tag = e.target.tagName;
62+
if (tag != "INPUT" && tag != "TEXTAREA") {
63+
const filterInput = findRef('.documentableFilter input.filterableInput');
64+
if (filterInput != null) {
65+
// if we focus during this event handler, the `f` key gets typed into the input
66+
setTimeout(() => filterInput.focus(), 1);
67+
}
68+
}
69+
}
70+
})
5771
});
5872

5973
var zoom;

0 commit comments

Comments
 (0)