8350638: Make keyboard navigation more usable in API docs

Reviewed-by: liach, nbenalla
This commit is contained in:
Hannes Wallnöfer 2025-03-10 13:28:42 +00:00
parent 4867a4c89e
commit e90b6bdb87
21 changed files with 320 additions and 143 deletions

View File

@ -35,6 +35,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
import jdk.javadoc.internal.html.Content;
import jdk.javadoc.internal.html.ContentBuilder;
import jdk.javadoc.internal.html.Entity;
import jdk.javadoc.internal.html.HtmlId;
import jdk.javadoc.internal.html.HtmlTree;
import jdk.javadoc.internal.html.Text;
@ -172,6 +173,27 @@ public class HelpWriter extends HtmlDocletWriter {
.add(searchRefer);
navSection.add(section);
}
// Keyboard Navigation
section = newHelpSection(contents.getContent("doclet.help.keyboard_navigation.title"),
HtmlIds.HELP_KEYBOARD_NAVIGATION);
var keyboardPara = HtmlTree.P(contents.getContent("doclet.help.keyboard_navigation.intro"));
var keyboardList = HtmlTree.UL();
if (options.createIndex()) {
keyboardList.add(HtmlTree.LI(contents.getContent("doclet.help.keyboard_navigation.index",
HtmlTree.KBD(Text.of("/")))));
}
keyboardList.add(HtmlTree.LI(contents.getContent("doclet.help.keyboard_navigation.filter",
HtmlTree.KBD(Text.of(".")))));
keyboardList.add(HtmlTree.LI(contents.getContent("doclet.help.keyboard_navigation.escape",
HtmlTree.KBD(Text.of("Esc")))));
keyboardList.add(HtmlTree.LI(contents.getContent("doclet.help.keyboard_navigation.search",
HtmlTree.KBD(Text.of("Tab")), HtmlTree.KBD(Entity.of("downarrow")),
HtmlTree.KBD(Entity.of("uparrow")))));
keyboardList.add(HtmlTree.LI(contents.getContent("doclet.help.keyboard_navigation.tabs",
HtmlTree.KBD(Entity.of("leftarrow")), HtmlTree.KBD(Entity.of("rightarrow")))));
navSection.add(section.add(keyboardPara.add(keyboardList)));
tableOfContents.popNestedList();
return content;

View File

@ -92,6 +92,7 @@ public class HtmlIds {
static final HtmlId FIELD_SUMMARY = HtmlId.of("field-summary");
static final HtmlId FOR_REMOVAL = HtmlId.of("for-removal");
static final HtmlId HELP_NAVIGATION = HtmlId.of("help-navigation");
static final HtmlId HELP_KEYBOARD_NAVIGATION = HtmlId.of("help-keyboard-navigation");
static final HtmlId HELP_PAGES = HtmlId.of("help-pages");
static final HtmlId HELP_RELEASES = HtmlId.of("help-releases");
static final HtmlId METHOD_DETAIL = HtmlId.of("method-detail");

View File

@ -498,7 +498,8 @@ public class Navigation {
var inputText = HtmlTree.INPUT(HtmlAttr.InputType.TEXT, HtmlIds.SEARCH_INPUT)
.put(HtmlAttr.PLACEHOLDER, resources.getText("doclet.search_placeholder"))
.put(HtmlAttr.ARIA_LABEL, resources.getText("doclet.search_in_documentation"))
.put(HtmlAttr.AUTOCOMPLETE, "off");
.put(HtmlAttr.AUTOCOMPLETE, "off")
.put(HtmlAttr.SPELLCHECK, "false");
var inputReset = HtmlTree.INPUT(HtmlAttr.InputType.RESET, HtmlIds.RESET_SEARCH)
.put(HtmlAttr.VALUE, resources.getText("doclet.search_reset"));
var searchDiv = HtmlTree.DIV(HtmlStyles.navListSearch)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,6 +32,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
import jdk.javadoc.internal.html.Content;
import jdk.javadoc.internal.html.ContentBuilder;
import jdk.javadoc.internal.html.Entity;
import jdk.javadoc.internal.html.HtmlAttr;
import jdk.javadoc.internal.html.HtmlId;
import jdk.javadoc.internal.html.HtmlTag;
@ -85,7 +86,8 @@ public class SearchWriter extends HtmlDocletWriter {
.add(HtmlTree.DIV(HtmlTree.INPUT(HtmlAttr.InputType.TEXT, HtmlId.of("page-search-input"))
.put(HtmlAttr.PLACEHOLDER, resources.getText("doclet.search_placeholder"))
.put(HtmlAttr.ARIA_LABEL, resources.getText("doclet.search_in_documentation"))
.put(HtmlAttr.AUTOCOMPLETE, "off"))
.put(HtmlAttr.AUTOCOMPLETE, "off")
.put(HtmlAttr.SPELLCHECK, "false"))
.add(HtmlTree.INPUT(HtmlAttr.InputType.RESET, HtmlId.of("page-search-reset"))
.put(HtmlAttr.VALUE, resources.getText("doclet.search_reset"))
.put(HtmlAttr.STYLE, "margin: 6px;"))
@ -93,7 +95,10 @@ public class SearchWriter extends HtmlDocletWriter {
.add(HtmlTree.SUMMARY(contents.getContent("doclet.search.show_more"))
.setId(HtmlId.of("page-search-expand")))))
.add(HtmlTree.DIV(HtmlStyles.pageSearchInfo, helpSection)
.add(HtmlTree.P(contents.getContent("doclet.search.keyboard_info")))
.add(HtmlTree.P(contents.getContent("doclet.search.keyboard_info",
HtmlTree.KBD(Text.of("Ctrl")), HtmlTree.KBD(Text.of("Cmd")),
new ContentBuilder(HtmlTree.KBD(Entity.of("leftarrow")), Text.of("/"),
HtmlTree.KBD(Entity.of("rightarrow"))))))
.add(HtmlTree.P(contents.getContent("doclet.search.browser_info")))
.add(HtmlTree.SPAN(Text.of("link"))
.setId(HtmlId.of("page-search-link")))

View File

@ -47,7 +47,8 @@ public class TableOfContents {
*/
public TableOfContents(HtmlDocletWriter writer) {
this.writer = writer;
listBuilder = new ListBuilder(HtmlTree.OL(HtmlStyles.tocList));
listBuilder = new ListBuilder(HtmlTree.OL(HtmlStyles.tocList)
.put(HtmlAttr.TABINDEX, "-1"));
}
/**
@ -96,18 +97,21 @@ public class TableOfContents {
.add(HtmlTree.INPUT(HtmlAttr.InputType.TEXT, HtmlStyles.filterInput)
.put(HtmlAttr.PLACEHOLDER, writer.resources.getText("doclet.filter_label"))
.put(HtmlAttr.ARIA_LABEL, writer.resources.getText("doclet.filter_table_of_contents"))
.put(HtmlAttr.AUTOCOMPLETE, "off"))
.put(HtmlAttr.AUTOCOMPLETE, "off")
.put(HtmlAttr.SPELLCHECK, "false"))
.add(HtmlTree.INPUT(HtmlAttr.InputType.RESET, HtmlStyles.resetFilter)
.put(HtmlAttr.TABINDEX, "-1")
.put(HtmlAttr.VALUE, writer.resources.getText("doclet.filter_reset")));
}
content.add(header);
content.add(listBuilder);
content.add(HtmlTree.BUTTON(HtmlStyles.hideSidebar)
.add(HtmlTree.SPAN(writer.contents.hideSidebar).add(Entity.NO_BREAK_SPACE))
.add(Entity.LEFT_POINTING_ANGLE));
content.add(HtmlTree.BUTTON(HtmlStyles.showSidebar)
.add(Entity.RIGHT_POINTING_ANGLE)
.add(HtmlTree.SPAN(Entity.NO_BREAK_SPACE).add(writer.contents.showSidebar)));
return content.add(listBuilder);
return content;
}
}

View File

@ -201,6 +201,18 @@ function copyToClipboard(content) {
document.execCommand("copy");
document.body.removeChild(textarea);
}
function resetInput(input, event, blur) {
if (input.value) {
input.value = "";
input.dispatchEvent(new InputEvent("input"));
} else if (blur) {
input.blur();
}
event.preventDefault();
}
function isInput(elem) {
return elem instanceof HTMLInputElement && elem.type === "text";
}
function switchCopyLabel(button, span) {
var copied = span.getAttribute("data-copied");
button.classList.add("visible");
@ -215,6 +227,82 @@ function switchCopyLabel(button, span) {
}, 100);
}, 1900);
}
function makeFilterWidget(sidebar, updateToc) {
if (!sidebar) {
return null;
}
const filterInput = sidebar.querySelector("input.filter-input");
const resetInput = sidebar.querySelector("input.reset-filter");
sidebar.addEventListener("keydown", e => {
if (e.ctrlKey || e.altKey || e.metaKey) {
return;
}
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
handleTocFocus(e);
} else if (filterInput && e.target !== filterInput) {
if (e.key === "Enter" && isTocLink(sidebar, e.target)) {
filterInput.value = "";
filterInput.dispatchEvent(new InputEvent("input"));
} else if (e.key.length === 1 || e.key === "Backspace") {
filterInput.focus();
}
}
});
if (filterInput) {
filterInput.removeAttribute("disabled");
filterInput.setAttribute("autocapitalize", "off");
filterInput.value = "";
filterInput.addEventListener("input", function(e) {
resetInput.style.visibility = filterInput.value ? "visible" : "hidden";
const pattern = filterInput.value ? filterInput.value.trim()
.replace(/[\[\]{}()*+?.\\^$|]/g, '\\$&')
.replace(/\s+/g, ".*") : "";
const filter = new RegExp(pattern, "i");
sidebar.querySelectorAll("ol.toc-list li").forEach((li) => {
if (filter.test(li.innerText)) {
// li.removeAttribute("style");
const selfMatch = filter.test(li.firstElementChild.innerText);
li.style.display = "block";
li.firstElementChild.style.opacity = selfMatch ? "100%" : "70%";
li.firstElementChild.tabIndex = selfMatch ? 0 : -1;
} else {
li.style.display = "none";
}
});
updateToc();
});
}
if (resetInput) {
resetInput.removeAttribute("disabled");
resetInput.addEventListener("click", (e) => {
filterInput.value = "";
filterInput.focus();
filterInput.dispatchEvent(new InputEvent("input"));
});
}
function handleTocFocus(event) {
let links = Array.from(sidebar.querySelectorAll("ol > li > a"))
.filter(link => link.offsetParent && link.tabIndex === 0);
let current = links.indexOf(document.activeElement);
if (event.key === "ArrowUp") {
if (current > 0) {
links[current - 1].focus({focusVisible: true});
} else if (filterInput) {
filterInput.focus();
}
} else if (event.key === "ArrowDown" && current < links.length - 1) {
links[current + 1].focus({focusVisible: true});
}
event.preventDefault();
}
function isTocLink(sidebar, elem) {
let links = Array.from(sidebar.querySelectorAll("ol > li > a"))
.filter(link => link.offsetParent && link.tabIndex === 0);
return links.indexOf(elem) > -1;
}
return sidebar;
}
function setTopMargin() {
// Dynamically set scroll margin to accomodate for draft header
var headerHeight = Math.ceil(document.querySelector("header").offsetHeight);
@ -237,61 +325,69 @@ document.addEventListener("DOMContentLoaded", function(e) {
if (subnav && subnav.lastElementChild) {
subnav.lastElementChild.scrollIntoView({ behavior: "instant", inline: "start", block: "nearest" });
}
const keymap = new Map();
const searchInput = document.getElementById("search-input")
|| document.getElementById("page-search-input");
if (searchInput) {
searchInput.addEventListener("focus", collapse);
keymap.set("/", searchInput);
}
const filterInput = document.querySelector("input.filter-input");
if (filterInput) {
keymap.set(".", filterInput);
}
// Clone TOC sidebar to header for mobile navigation
const navbar = document.querySelector("div#navbar-top");
const sidebar = document.querySelector(".main-grid nav.toc");
const main = document.querySelector(".main-grid main");
const mainnav = navbar.querySelector("ul.nav-list");
const toggleButton = document.querySelector("button#navbar-toggle-button");
const toc = sidebar ? sidebar.cloneNode(true) : null;
if (toc) {
navbar.appendChild(toc);
const tocMenu = sidebar ? sidebar.cloneNode(true) : null;
makeFilterWidget(sidebar, updateToc);
if (tocMenu) {
navbar.appendChild(tocMenu);
makeFilterWidget(tocMenu, updateToc);
var menuInput = tocMenu.querySelector("input.filter-input");
}
document.querySelectorAll("input.filter-input").forEach(function(input) {
input.removeAttribute("disabled");
input.setAttribute("autocapitalize", "off");
input.value = "";
input.addEventListener("input", function(e) {
const pattern = input.value ? input.value.trim()
.replace(/[\[\]{}()*+?.\\^$|]/g, '\\$&')
.replace(/\s+/g, ".*") : "";
input.nextElementSibling.style.display = pattern ? "inline" : "none";
const filter = new RegExp(pattern, "i");
input.parentNode.parentNode.querySelectorAll("ol.toc-list li").forEach((li) => {
if (filter.test(li.innerText)) {
li.removeAttribute("style");
} else {
li.style.display = "none";
}
});
if (expanded) {
expand();
document.addEventListener("keydown", (e) => {
if (e.ctrlKey || e.altKey || e.metaKey) {
return;
}
if (!isInput(e.target) && keymap.has(e.key)) {
var elem = keymap.get(e.key);
if (elem === filterInput && !elem.offsetParent) {
elem = getVisibleFilterInput(true);
}
});
});
document.querySelectorAll("input.reset-filter").forEach((button) => {
button.removeAttribute("disabled");
button.addEventListener("click", (e) => {
const input = button.previousElementSibling;
input.value = "";
input.dispatchEvent(new InputEvent("input"));
input.focus();
elem.focus();
elem.select();
e.preventDefault();
} else if (e.key === "Escape") {
if (expanded) {
expand();
collapse();
e.preventDefault();
} else if (e.target.id === "page-search-input") {
resetInput(e.target, e, false);
} else if (isInput(e.target)) {
resetInput(e.target, e, true);
} else {
prevHash = null;
handleScroll();
var filter = getVisibleFilterInput(false);
if (filter && filter.value) {
resetInput(filterInput, e, true);
}
}
})
}
});
var expanded = false;
var windowWidth;
var bodyHeight;
function collapse(e) {
function collapse() {
if (expanded) {
mainnav.removeAttribute("style");
if (toc) {
toc.removeAttribute("style");
if (tocMenu) {
tocMenu.removeAttribute("style");
if (filterInput) {
keymap.set(".", filterInput);
}
}
toggleButton.classList.remove("expanded")
toggleButton.setAttribute("aria-expanded", "false");
@ -304,18 +400,42 @@ document.addEventListener("DOMContentLoaded", function(e) {
mainnav.style.removeProperty("height");
var maxHeight = window.innerHeight - subnav.offsetTop + 4;
var expandedHeight = Math.min(maxHeight, mainnav.scrollHeight + 10);
if (toc) {
toc.style.display = "flex";
if (tocMenu) {
tocMenu.style.display = "flex";
expandedHeight = Math.min(maxHeight,
Math.max(expandedHeight, toc.querySelector("div.toc-header").offsetHeight
+ toc.querySelector("ol.toc-list").scrollHeight + 10));
toc.style.height = expandedHeight + "px";
Math.max(expandedHeight, tocMenu.querySelector("div.toc-header").offsetHeight
+ tocMenu.querySelector("ol.toc-list").scrollHeight + 10));
tocMenu.style.height = expandedHeight + "px";
if (menuInput) {
keymap.set(".", menuInput);
}
}
mainnav.style.height = expandedHeight + "px";
toggleButton.classList.add("expanded");
toggleButton.setAttribute("aria-expanded", "true");
windowWidth = window.innerWidth;
}
function updateToc() {
if (expanded) {
expand();
} else {
prevHash = null;
handleScroll();
}
}
function getVisibleFilterInput(show) {
if (sidebar && sidebar.offsetParent) {
if (show) {
showSidebar();
}
return filterInput;
} else {
if (show) {
expand();
}
return menuInput;
}
}
toggleButton.addEventListener("click", (e) => {
if (expanded) {
collapse();
@ -323,17 +443,12 @@ document.addEventListener("DOMContentLoaded", function(e) {
expand();
}
});
if (toc) {
toc.querySelectorAll("a").forEach((link) => {
if (tocMenu) {
tocMenu.querySelectorAll("a").forEach((link) => {
link.addEventListener("click", collapse);
});
}
document.addEventListener('keydown', (e) => {
if (e.key === "Escape") collapse();
});
document.querySelector("main").addEventListener("click", collapse);
const searchInput = document.getElementById("search-input");
if (searchInput) searchInput.addEventListener("focus", collapse);
document.querySelectorAll("h1, h2, h3, h4, h5, h6")
.forEach((hdr, idx) => {
// Create anchor links for headers with an associated id attribute
@ -412,24 +527,27 @@ document.addEventListener("DOMContentLoaded", function(e) {
}
}
}
function hideSidebar() {
sidebar.classList.add("hide-sidebar");
sessionStorage.setItem("sidebar", "hidden");
}
function showSidebar() {
sidebar.classList.remove("hide-sidebar");
sessionStorage.removeItem("sidebar");
initSectionData();
handleScroll();
}
if (sidebar) {
initSectionData();
document.querySelectorAll("a[href^='#']").forEach((link) => {
link.addEventListener("click", (e) => {
link.blur();
scrollTimeoutNeeded = true;
setSelected(link.getAttribute("href"));
})
});
sidebar.querySelector("button.hide-sidebar").addEventListener("click", () => {
sidebar.classList.add("hide-sidebar");
sessionStorage.setItem("sidebar", "hidden");
});
sidebar.querySelector("button.show-sidebar").addEventListener("click", () => {
sidebar.classList.remove("hide-sidebar");
sessionStorage.removeItem("sidebar");
initSectionData();
handleScroll();
});
sidebar.querySelector("button.hide-sidebar").addEventListener("click", hideSidebar);
sidebar.querySelector("button.show-sidebar").addEventListener("click", showSidebar);
window.addEventListener("hashchange", (e) => {
scrollTimeoutNeeded = true;
});

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
@ -390,7 +390,6 @@ $(function() {
minLength: 1,
delay: 200,
source: function(request, response) {
reset.css("display", "inline");
if (request.term.trim() === "") {
return this.close();
}
@ -403,12 +402,6 @@ $(function() {
$("#search-input").empty();
}
},
close: function(event, ui) {
reset.css("display", search.val() ? "inline" : "none");
},
change: function(event, ui) {
reset.css("display", search.val() ? "inline" : "none");
},
autoFocus: true,
focus: function(event, ui) {
return false;
@ -420,17 +413,15 @@ $(function() {
if (ui.item.indexItem) {
var url = getURL(ui.item.indexItem, ui.item.category);
window.location.href = pathtoroot + url;
$("#search-input").focus();
}
}
});
search.val('');
search.on("input", () => reset.css("visibility", search.val() ? "visible" : "hidden"))
search.prop("disabled", false);
search.attr("autocapitalize", "off");
reset.prop("disabled", false);
reset.click(function() {
search.val('').focus();
reset.css("display", "none");
});
search.focus();
});

View File

@ -198,9 +198,10 @@ doclet.search.help_page_link=help page
# 0: a link to the help page with text above
doclet.search.help_page_info= \
The {0} provides an introduction to the scope and syntax of JavaDoc search.
# 0: [Ctrl] 1: [Cmd] 2: [<]/[>] (left and right arrow keys)
doclet.search.keyboard_info= \
You can use the <ctrl> or <cmd> keys in combination with the left and right arrow \
keys to switch between result tabs in this page.
You can use the {0} or {1} key in combination with the {2} arrow \
keys to switch between result tabs in this page while searching.
doclet.search.browser_info= \
The URL template below may be used to configure this page as a search engine \
in browsers that support this feature. It has been tested to work in Google \
@ -385,6 +386,18 @@ doclet.help.search.refer=Refer to the {0} for a full description of search featu
doclet.help.search.spec.url=https://docs.oracle.com/en/java/javase/{0}/docs/specs/javadoc/javadoc-search-spec.html
# The title for the Javadoc Search Specification
doclet.help.search.spec.title=Javadoc Search Specification
doclet.help.keyboard_navigation.title=Keyboard Navigation
doclet.help.keyboard_navigation.intro=Documentation pages provide keyboard shortcuts to facilitate \
access to common navigation tasks.
# Arguments in the messages below are <kbd> elements representing various keyboard keys
doclet.help.keyboard_navigation.index=Type {0} to access the search input field in any page.
doclet.help.keyboard_navigation.filter=Type {0} to access the filter input field in the sidebar \
of class pages.
doclet.help.keyboard_navigation.escape=Type {0} to clear the input and release keyboard focus in \
any input field.
doclet.help.keyboard_navigation.search=Type {0}/{1}/{2} to select list items after entering a \
search term in a search or filter input field.
doclet.help.keyboard_navigation.tabs=Type {0}/{1} to switch between tabs in tabbed summary tables.
doclet.help.releases.head=Release Details
doclet.help.releases.body.specify.top-level=\
The details for each module, package, class or interface \

View File

@ -465,7 +465,8 @@ dl.name-value > dd {
.main-grid nav.toc button span {
display: none;
}
.main-grid nav.toc button:hover {
.main-grid nav.toc button:hover,
.main-grid nav.toc button:focus {
color: var(--body-text-color);
border: 1px solid var(--subnav-background-color);
}
@ -474,10 +475,11 @@ dl.name-value > dd {
color: var(--link-color-active);
}
.main-grid nav.toc button:hover span,
.main-grid nav.toc button:active span {
.main-grid nav.toc button:focus span {
display: inline;
}
.main-grid nav.toc button:hover {
.main-grid nav.toc button:hover,
.main-grid nav.toc button:focus {
box-shadow: 1px 1px 5px rgba(0,0,0,0.2);
}
.main-grid nav.toc.hide-sidebar {
@ -511,13 +513,10 @@ nav.toc > ol.toc-list {
}
nav.toc ol.toc-list {
list-style: none;
font-size: var(--nav-font-size);
padding-left: 0;
margin: 0;
}
nav.toc ol.toc-list li {
margin: 0;
font-size: var(--nav-font-size);
}
a.current-selection {
font-weight: bold;
}
@ -536,6 +535,11 @@ nav.toc a:hover {
nav.toc a.current-selection {
background-color: var(--toc-highlight-color);
}
nav.toc a:focus-visible {
background-color: var(--selected-background-color);
color: var(--selected-text-color);
outline: none;
}
/*
* Styles for lists.
*/
@ -1015,9 +1019,9 @@ input#search-input {
margin: 0;
}
input.filter-input {
width: 44%;
max-width: 140px;
margin: 0 4px;
min-width: 40px;
width: 180px;
margin: 0 -8px 0 5px;
padding-right: 18px;
}
input#reset-search, input.reset-filter {
@ -1029,8 +1033,10 @@ input#reset-search, input.reset-filter {
border-radius:0;
width:12px;
height:12px;
min-width:12px;
min-height:12px;
font-size:0;
display:none;
visibility:hidden;
}
input#reset-search {
position:absolute;
@ -1039,13 +1045,25 @@ input#reset-search {
}
input.reset-filter {
position: relative;
right: 20px;
right: 10px;
top: 0;
}
input::placeholder {
color:var(--search-input-placeholder-color);
opacity: 1;
}
input:focus::placeholder {
color: transparent;
}
kbd {
background-color: #eeeeee;
border: 1px solid #b0b0b0;
border-radius: 3px;
padding: 0 4px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 2px 0 0 rgba(255, 255, 255, 0.6) inset;
font-size: 0.9em;
font-weight: bold;
}
.search-tag-desc-result {
font-style:italic;
font-size:11px;

View File

@ -233,7 +233,7 @@ doclet.Type=Type
doclet.Modifier_and_Type=Modifier and Type
doclet.Implementation=Implementation(s):
doclet.search=Search
doclet.search_placeholder=Search
doclet.search_placeholder=Search documentation (type /)
doclet.search_in_documentation=Search in documentation
doclet.search_reset=Reset
doclet.Field=Field
@ -251,7 +251,7 @@ doclet.Value=Value
doclet.table_of_contents=Table of contents
doclet.hide_sidebar=Hide sidebar
doclet.show_sidebar=Show sidebar
doclet.filter_label=Filter
doclet.filter_label=Filter contents (type .)
doclet.filter_table_of_contents=Filter table of contents
doclet.filter_reset=Reset
doclet.linkMismatch_PackagedLinkedtoModule=The code being documented uses packages in the unnamed module, \

View File

@ -716,6 +716,17 @@ public class HtmlTree extends Content {
.setStyle(style)
.put(HtmlAttr.DISABLED, "");
}
/**
* Creates a {@code KBD} element with the given content.
*
* @param body the content
* @return the element
*/
public static HtmlTree KBD(Content body) {
return new HtmlTree(HtmlTag.KBD).add(body);
}
/**
* Creates an HTML {@code LABEL} element with the given content.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -73,7 +73,7 @@ public class TestAnnotationTypes extends JavadocTester {
checkOutput("pkg/AnnotationType.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#annotation-interface-required-element-summary" tabindex="0">Required Element Summary</a></li>
<li><a href="#annotation-interface-optional-element-summary" tabindex="0">Optional Element Summary</a></li>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -116,8 +116,7 @@ public class TestConstantValuesPage extends JavadocTester {
<li><a href="#p1.p2b" tabindex="0">p1.p2b.*</a></li>
</ol>
</li>
</ol>
</nav>""");
</ol>""");
}
/**
@ -152,8 +151,7 @@ public class TestConstantValuesPage extends JavadocTester {
<li><a href="#unnamed-package" tabindex="0">Unnamed Package</a></li>
</ol>
</li>
</ol>
</nav>""");
</ol>""");
}
/**
@ -196,8 +194,7 @@ public class TestConstantValuesPage extends JavadocTester {
<li><a href="#p1.p2a" tabindex="0">p1.p2a.*</a></li>
</ol>
</li>
</ol>
</nav>""");
</ol>""");
}
/**
@ -267,7 +264,6 @@ public class TestConstantValuesPage extends JavadocTester {
<li><a href="#p.q" tabindex="0">p.q.*</a></li>
</ol>
</li>
</ol>
</nav>""");
</ol>""");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -314,12 +314,7 @@ public class TestMarkdownHeadings extends JavadocTester {
checkOutput("p/C.html", true,
// note only the level 1 headings in the class description
"""
<div class="toc-header">Contents&nbsp;
<input type="text" class="filter-input" disabled placeholder="Filter" aria-label="Filter table of contents" autocomplete="off">
<input type="reset" class="reset-filter" disabled value="Reset">
</div>
<button class="hide-sidebar"><span>Hide sidebar&nbsp;</span>&#10094;</button><button class="show-sidebar">&#10095;<span>&nbsp;Show sidebar</span></button>
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a>
<ol class="toc-list">
<li><a href="#atx-heading-code-underline-text-heading" tabindex="0">ATX heading code underline text</a></li>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @bug 8185151 8196200 8261976
* @bug 8185151 8196200 8261976 8350638
* @summary test that navigation summary links are not linked when there are no dependencies
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
@ -72,7 +72,7 @@ public class TestModuleServicesLink extends JavadocTester {
checkOutput("m/module-summary.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#packages-summary" tabindex="0">Packages</a></li>
<li><a href="#services-summary" tabindex="0">Services</a></li>
@ -98,7 +98,7 @@ public class TestModuleServicesLink extends JavadocTester {
checkOutput("m/module-summary.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#packages-summary" tabindex="0">Packages</a></li>
<li><a href="#services-summary" tabindex="0">Services</a></li>
@ -122,7 +122,7 @@ public class TestModuleServicesLink extends JavadocTester {
checkOutput("m/module-summary.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#packages-summary" tabindex="0">Packages</a></li>
</ol>""");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -722,7 +722,7 @@ public class TestModules extends JavadocTester {
void checkModuleSummary() {
checkOutput("moduleA/module-summary.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#packages-summary" tabindex="0">Packages</a></li>
<li><a href="#modules-summary" tabindex="0">Modules</a></li>
@ -748,7 +748,7 @@ public class TestModules extends JavadocTester {
""");
checkOutput("moduleB/module-summary.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#packages-summary" tabindex="0">Packages</a></li>
<li><a href="#services-summary" tabindex="0">Services</a></li>
@ -897,7 +897,7 @@ public class TestModules extends JavadocTester {
</div>""");
checkOutput("moduleA/module-summary.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#packages-summary" tabindex="0">Packages</a></li>
<li><a href="#modules-summary" tabindex="0">Modules</a></li>
@ -912,7 +912,7 @@ public class TestModules extends JavadocTester {
-tab1"><a href="testpkgmdltags/package-summary.html">testpkgmdltags</a></div>
<div class="col-last even-row-color package-summary-table package-summary-table-tab1">&nbsp;</div>""",
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#packages-summary" tabindex="0">Packages</a></li>
<li><a href="#modules-summary" tabindex="0">Modules</a></li>
@ -960,7 +960,7 @@ public class TestModules extends JavadocTester {
<div class="col-last even-row-color package-summary-table package-summary-table-tab1">&nbsp;</div>""");
checkOutput("moduleB/module-summary.html", found,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#packages-summary" tabindex="0">Packages</a></li>
<li><a href="#services-summary" tabindex="0">Services</a></li>
@ -1037,7 +1037,7 @@ public class TestModules extends JavadocTester {
<div class="col-last even-row-color package-summary-table package-summary-table-tab3">&nbsp;</div>""");
checkOutput("moduleB/module-summary.html", found,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#packages-summary" tabindex="0">Packages</a></li>
<li><a href="#modules-summary" tabindex="0">Modules</a></li>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,7 +24,7 @@
/*
* @test
* @bug 7025314 8023700 7198273 8025633 8026567 8081854 8196027 8182765
* 8196200 8196202 8223378 8258659 8261976 8320458 8329537
* 8196200 8196202 8223378 8258659 8261976 8320458 8329537 8350638
* @summary Make sure the Next/Prev Class links iterate through all types.
* Make sure the navagation is 2 columns, not 3.
* @library /tools/lib ../../lib
@ -185,7 +185,7 @@ public class TestNavigation extends JavadocTester {
<li><a href="A.X.html" class="current-selection">X</a></li>
</ol>""",
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#nested-class-summary" tabindex="0">Nested Class Summary</a></li>
<li><a href="#field-summary" tabindex="0">Field Summary</a></li>
@ -216,7 +216,7 @@ public class TestNavigation extends JavadocTester {
<li><a href="A.Y.html" class="current-selection">Y</a></li>
</ol>""",
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#nested-class-summary" tabindex="0">Nested Class Summary</a></li>
<li><a href="#field-summary" tabindex="0">Field Summary</a></li>
@ -238,7 +238,7 @@ public class TestNavigation extends JavadocTester {
<li><a href="A.X.IC.html" class="current-selection">IC</a></li>
</ol>""",
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#constructor-summary" tabindex="0">Constructor Summary</a></li>
<li><a href="#method-summary" tabindex="0">Method Summary</a></li>
@ -251,7 +251,7 @@ public class TestNavigation extends JavadocTester {
checkOrder("pkg1/C.html",
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#constructor-summary" tabindex="0">Constructor Summary</a></li>
<li><a href="#method-summary" tabindex="0">Method Summary</a></li>
@ -264,7 +264,7 @@ public class TestNavigation extends JavadocTester {
checkOrder("pkg1/InterfaceWithNoMembers.html",
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
</ol>""");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,7 +24,7 @@
/*
* @test
* @bug 8189841 8253117 8263507 8320458
* @bug 8189841 8253117 8263507 8320458 8350638
* @summary Error in alternate row coloring in package-summary files
* @summary Improve structure of package summary pages
* @library ../../lib/
@ -51,14 +51,14 @@ public class TestPackageSummary extends JavadocTester {
checkOutput("pkg/package-summary.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#class-summary" tabindex="0">Classes and Interfaces</a></li>
</ol>
""");
checkOutput("pkg1/package-summary.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#related-package-summary" tabindex="0">Related Packages</a></li>
<li><a href="#class-summary" tabindex="0">Classes and Interfaces</a></li>
@ -66,7 +66,7 @@ public class TestPackageSummary extends JavadocTester {
""");
checkOutput("pkg1/sub/package-summary.html", true,
"""
<ol class="toc-list">
<ol class="toc-list" tabindex="-1">
<li><a href="#" tabindex="0">Description</a></li>
<li><a href="#related-package-summary" tabindex="0">Related Packages</a></li>
<li><a href="#class-summary" tabindex="0">Classes and Interfaces</a></li>

View File

@ -26,7 +26,7 @@
* @bug 8141492 8071982 8141636 8147890 8166175 8168965 8176794 8175218 8147881
* 8181622 8182263 8074407 8187521 8198522 8182765 8199278 8196201 8196202
* 8184205 8214468 8222548 8223378 8234746 8241219 8254627 8247994 8263528
* 8266808 8248863 8305710 8318082 8347058
* 8266808 8248863 8305710 8318082 8347058 8350638
* @summary Test the search feature of javadoc.
* @library ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@ -433,8 +433,8 @@ public class TestSearch extends JavadocTester {
<li><a href="search.html">Search</a></li>""",
"""
<div class="nav-list-search">
<input type="text" id="search-input" disabled placeholder="Search" aria-label="S\
earch in documentation" autocomplete="off">
<input type="text" id="search-input" disabled placeholder="Search documentation \
(type /)" aria-label="Search in documentation" autocomplete="off" spellcheck="false">
<input type="reset" id="reset-search" disabled value="Reset">
</div>""");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -133,8 +133,8 @@ public class TestSpecTag extends JavadocTester {
<div class="nav-content">
<ol class="sub-nav-list"></ol>
<div class="nav-list-search">
<input type="text" id="search-input" disabled placeholder="Search" aria-label="S\
earch in documentation" autocomplete="off">
<input type="text" id="search-input" disabled placeholder="Search documentation \
(type /)" aria-label="Search in documentation" autocomplete="off" spellcheck="false">
<input type="reset" id="reset-search" disabled value="Reset">
</div>
</div>

View File

@ -126,8 +126,10 @@ public class TestStylesheet extends JavadocTester {
border-radius:0;
width:12px;
height:12px;
min-width:12px;
min-height:12px;
font-size:0;
display:none;
visibility:hidden;
}""",
"""
::placeholder {