Skip to content

Improvements to search UX #12568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion scaladoc-js/resources/scaladoc-searchbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@

.scaladoc-searchbar-result a {
color: #1f2326;
/* for some reason, with display:block if there's a wrap between the
* search result text and the location span, the dead space to the
* left of the location span doesn't get treated as part of the block,
* which defeats the purpose of making the <a> a block element.
* But inline-block with width:100% works as desired.
*/
display: inline-block;
width: 100%;
text-indent: -20px;
padding-left: 20px;
}
Expand Down Expand Up @@ -142,4 +150,3 @@
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}

29 changes: 27 additions & 2 deletions scaladoc-js/src/searchbar/SearchbarComponent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):

wrapper.appendChild(icon)
wrapper.appendChild(resultA)
wrapper.appendChild(location)
resultA.appendChild(location)
wrapper.addEventListener("mouseover", {
case e: MouseEvent => handleHover(wrapper)
})
Expand Down Expand Up @@ -64,6 +64,8 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
document.body.appendChild(rootDiv)
input.focus()
}
// open the search if the user hits the `s` key when not focused on a text input
document.body.addEventListener("keydown", (e: KeyboardEvent) => handleGlobalKeyDown(e))

val element = createNestingDiv("search-content")(
createNestingDiv("search-container")(
Expand All @@ -75,7 +77,6 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
document.getElementById("scaladoc-searchBar").appendChild(element)
element


private val input: html.Input =
val element = document.createElement("input").asInstanceOf[html.Input]
element.id = "scaladoc-searchbar-input"
Expand Down Expand Up @@ -111,6 +112,7 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
if e.keyCode == 40 then handleArrowDown()
else if e.keyCode == 38 then handleArrowUp()
else if e.keyCode == 13 then handleEnter()
else if e.keyCode == 27 then handleEscape()
})
element.id = "scaladoc-searchbar"
element.appendChild(input)
Expand Down Expand Up @@ -151,6 +153,12 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
selectedElement.click()
}
}
private def handleEscape() = {
// clear the search input and close the search
input.value = ""
handleNewQuery("")
document.body.removeChild(rootDiv)
}

private def handleHover(elem: html.Element) = {
val selectedElement = resultsDiv.querySelector("[selected]")
Expand All @@ -160,4 +168,21 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
elem.setAttribute("selected","")
}

private def handleGlobalKeyDown(e: KeyboardEvent) = {
// if the user presses the "S" key while not focused on an input, open the search
if (e.key == "s" || e.key == "/") {
val tag = e.target.asInstanceOf[html.Element].tagName
if (tag != "INPUT" && tag != "TEXTAREA") {
if (!document.body.contains(rootDiv)) {
// Firefox's "quick find" uses "/" as a trigger; prevent that.
e.preventDefault()

document.body.appendChild(rootDiv)
// if we focus during the event handler, the `s` gets typed into the input
window.setTimeout(() => input.focus(), 1.0)
}
}
}
}

handleNewQuery("")
12 changes: 12 additions & 0 deletions scaladoc/resources/dotty_res/scripts/components/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,27 @@ class Input extends Component {

this.inputRef = findRef(".filterableInput");
this.onChangeFn = withEvent(this.inputRef, "input", this.onInputChange);
this.onKeydownFn = withEvent(this.inputRef, "keydown", this.onKeydown);
}

onInputChange = ({ currentTarget: { value } }) => {
this.props.onInputChange(value);
};

onKeydown = (e) => {
// if the user hits Escape while typing in the filter input,
// clear the filter and un-focus the input
if (e.keyCode == 27) {
this.inputRef.value = '';
this.onInputChange(e);
setTimeout(() => this.inputRef.blur(), 1);
}
}

componentWillUnmount() {
if (this.onChangeFn) {
this.onChangeFn();
this.onKeydownFn();
}
}
}
14 changes: 14 additions & 0 deletions scaladoc/resources/dotty_res/scripts/ux.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ window.addEventListener("DOMContentLoaded", () => {
hljs.registerLanguage("scala", highlightDotty);
hljs.registerAliases(["dotty", "scala3"], "scala");
hljs.initHighlighting();

/* listen for the `F` key to be pressed, to focus on the member filter input (if it's present) */
document.body.addEventListener('keydown', e => {
if (e.key == "f") {
const tag = e.target.tagName;
if (tag != "INPUT" && tag != "TEXTAREA") {
const filterInput = findRef('.documentableFilter input.filterableInput');
if (filterInput != null) {
// if we focus during this event handler, the `f` key gets typed into the input
setTimeout(() => filterInput.focus(), 1);
}
}
}
})
});

var zoom;
Expand Down