001/* 002 * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package org.jdrupes.mdoclet.internal.doclets.formats.html; 027 028import static org.jdrupes.mdoclet.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; 029 030import java.util.ArrayList; 031import java.util.List; 032import java.util.Set; 033 034import javax.lang.model.element.Element; 035import javax.lang.model.element.ModuleElement; 036import javax.lang.model.element.PackageElement; 037import javax.lang.model.element.TypeElement; 038 039import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.ContentBuilder; 040import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Entity; 041import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlAttr; 042import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlStyle; 043import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlTree; 044import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Links; 045import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.TagName; 046import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Text; 047import org.jdrupes.mdoclet.internal.doclets.toolkit.Content; 048import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocFile; 049import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocLink; 050import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocPath; 051import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocPaths; 052import org.jdrupes.mdoclet.internal.doclets.toolkit.util.VisibleMemberTable; 053 054/** 055 * Factory for navigation bar. 056 * 057 * <p> 058 * <b>This is NOT part of any supported API. If you write code that depends on this, you do so at 059 * your own risk. This code and its internal interfaces are subject to change or deletion without 060 * notice.</b> 061 */ 062public class Navigation { 063 064 private final HtmlConfiguration configuration; 065 private final HtmlOptions options; 066 private final Element element; 067 private final Contents contents; 068 private final HtmlIds htmlIds; 069 private final DocPath path; 070 private final DocPath pathToRoot; 071 private final Links links; 072 private final PageMode documentedPage; 073 private Content navLinkModule; 074 private Content navLinkPackage; 075 private Content navLinkClass; 076 private Content userHeader; 077 private final String rowListTitle; 078 private final Content searchLabel; 079 private final String searchPlaceholder; 080 private SubNavLinks subNavLinks; 081 082 public enum PageMode { 083 ALL_CLASSES, 084 ALL_PACKAGES, 085 CLASS, 086 CONSTANT_VALUES, 087 DEPRECATED, 088 DOC_FILE, 089 EXTERNAL_SPECS, 090 HELP, 091 INDEX, 092 MODULE, 093 NEW, 094 OVERVIEW, 095 PACKAGE, 096 PREVIEW, 097 SERIALIZED_FORM, 098 SEARCH, 099 SYSTEM_PROPERTIES, 100 TREE, 101 USE; 102 } 103 104 /** 105 * An interface to provide links for the subnavigation area. 106 */ 107 public interface SubNavLinks { 108 /** 109 * {@return a list of links to display in the subnavigation area} 110 * Links should be wrapped in {@code HtmlTree.LI} elements as they are 111 * displayed within an unordered list. 112 */ 113 List<Content> getSubNavLinks(); 114 } 115 116 /** 117 * Creates a {@code Navigation} object for a specific file, to be written in a specific HTML 118 * version. 119 * 120 * @param element element being documented. null if its not an element documentation page 121 * @param configuration the configuration object 122 * @param page the kind of page being documented 123 * @param path the DocPath object 124 */ 125 public Navigation(Element element, HtmlConfiguration configuration, 126 PageMode page, DocPath path) { 127 this.configuration = configuration; 128 this.options = configuration.getOptions(); 129 this.element = element; 130 this.contents = configuration.getContents(); 131 this.htmlIds = configuration.htmlIds; 132 this.documentedPage = page; 133 this.path = path; 134 this.pathToRoot = path.parent().invert(); 135 this.links = new Links(path); 136 this.rowListTitle 137 = configuration.getDocResources().getText("doclet.Navigation"); 138 this.searchLabel = contents.getContent("doclet.search"); 139 this.searchPlaceholder = configuration.getDocResources() 140 .getText("doclet.search_placeholder"); 141 } 142 143 public Navigation setNavLinkModule(Content navLinkModule) { 144 this.navLinkModule = navLinkModule; 145 return this; 146 } 147 148 public Navigation setNavLinkPackage(Content navLinkPackage) { 149 this.navLinkPackage = navLinkPackage; 150 return this; 151 } 152 153 public Navigation setNavLinkClass(Content navLinkClass) { 154 this.navLinkClass = navLinkClass; 155 return this; 156 } 157 158 public Navigation setUserHeader(Content userHeader) { 159 this.userHeader = userHeader; 160 return this; 161 } 162 163 public Navigation setSubNavLinks(SubNavLinks subNavLinks) { 164 this.subNavLinks = subNavLinks; 165 return this; 166 } 167 168 /** 169 * Adds the links for the main navigation. 170 * 171 * @param target the content to which the main navigation will added 172 */ 173 private void addMainNavLinks(Content target) { 174 switch (documentedPage) { 175 case OVERVIEW: 176 addActivePageLink(target, contents.overviewLabel, 177 options.createOverview()); 178 addModuleLink(target); 179 addPackageLink(target); 180 addPageLabel(target, contents.classLabel, true); 181 addPageLabel(target, contents.useLabel, options.classUse()); 182 addTreeLink(target); 183 addPreviewLink(target); 184 addNewLink(target); 185 addDeprecatedLink(target); 186 addIndexLink(target); 187 addHelpLink(target); 188 break; 189 case MODULE: 190 addOverviewLink(target); 191 addActivePageLink(target, contents.moduleLabel, 192 configuration.showModules); 193 addPackageLink(target); 194 addPageLabel(target, contents.classLabel, true); 195 addPageLabel(target, contents.useLabel, options.classUse()); 196 addTreeLink(target); 197 addPreviewLink(target); 198 addNewLink(target); 199 addDeprecatedLink(target); 200 addIndexLink(target); 201 addHelpLink(target); 202 break; 203 case PACKAGE: 204 addOverviewLink(target); 205 addModuleOfElementLink(target); 206 addActivePageLink(target, contents.packageLabel, true); 207 addPageLabel(target, contents.classLabel, true); 208 if (options.classUse()) { 209 addItemToList(target, links.createLink(DocPaths.PACKAGE_USE, 210 contents.useLabel, "")); 211 } 212 if (options.createTree()) { 213 addItemToList(target, links.createLink(DocPaths.PACKAGE_TREE, 214 contents.treeLabel, "")); 215 } 216 addPreviewLink(target); 217 addNewLink(target); 218 addDeprecatedLink(target); 219 addIndexLink(target); 220 addHelpLink(target); 221 break; 222 case CLASS: 223 addOverviewLink(target); 224 addModuleOfElementLink(target); 225 addPackageSummaryLink(target); 226 addActivePageLink(target, contents.classLabel, true); 227 if (options.classUse()) { 228 addItemToList(target, 229 links.createLink( 230 DocPaths.CLASS_USE.resolve(path.basename()), 231 contents.useLabel)); 232 } 233 if (options.createTree()) { 234 addItemToList(target, links.createLink(DocPaths.PACKAGE_TREE, 235 contents.treeLabel, "")); 236 } 237 addPreviewLink(target); 238 addNewLink(target); 239 addDeprecatedLink(target); 240 addIndexLink(target); 241 addHelpLink(target); 242 break; 243 case USE: 244 addOverviewLink(target); 245 addModuleOfElementLink(target); 246 if (element instanceof PackageElement) { 247 addPackageSummaryLink(target); 248 addPageLabel(target, contents.classLabel, true); 249 } else { 250 addPackageOfElementLink(target); 251 addItemToList(target, navLinkClass); 252 } 253 addActivePageLink(target, contents.useLabel, options.classUse()); 254 if (element instanceof PackageElement) { 255 addItemToList(target, links.createLink(DocPaths.PACKAGE_TREE, 256 contents.treeLabel)); 257 } else { 258 addItemToList(target, 259 configuration.utils 260 .isEnclosingPackageIncluded((TypeElement) element) 261 ? links.createLink( 262 DocPath.parent.resolve(DocPaths.PACKAGE_TREE), 263 contents.treeLabel) 264 : links.createLink( 265 pathToRoot.resolve(DocPaths.OVERVIEW_TREE), 266 contents.treeLabel)); 267 } 268 addPreviewLink(target); 269 addNewLink(target); 270 addDeprecatedLink(target); 271 addIndexLink(target); 272 addHelpLink(target); 273 break; 274 case TREE: 275 addOverviewLink(target); 276 if (element == null) { 277 addPageLabel(target, contents.moduleLabel, 278 configuration.showModules); 279 addPageLabel(target, contents.packageLabel, true); 280 } else { 281 addModuleOfElementLink(target); 282 addPackageSummaryLink(target); 283 } 284 addPageLabel(target, contents.classLabel, true); 285 addPageLabel(target, contents.useLabel, options.classUse()); 286 addActivePageLink(target, contents.treeLabel, options.createTree()); 287 addPreviewLink(target); 288 addNewLink(target); 289 addDeprecatedLink(target); 290 addIndexLink(target); 291 addHelpLink(target); 292 break; 293 case DEPRECATED: 294 case INDEX: 295 case HELP: 296 case PREVIEW: 297 case NEW: 298 addOverviewLink(target); 299 addModuleLink(target); 300 addPackageLink(target); 301 addPageLabel(target, contents.classLabel, true); 302 addPageLabel(target, contents.useLabel, options.classUse()); 303 addTreeLink(target); 304 if (documentedPage == PageMode.PREVIEW) { 305 addActivePageLink(target, contents.previewLabel, 306 configuration.conditionalPages 307 .contains(HtmlConfiguration.ConditionalPage.PREVIEW)); 308 } else { 309 addPreviewLink(target); 310 } 311 if (documentedPage == PageMode.NEW) { 312 addActivePageLink(target, contents.newLabel, 313 configuration.conditionalPages 314 .contains(HtmlConfiguration.ConditionalPage.NEW)); 315 } else { 316 addNewLink(target); 317 } 318 if (documentedPage == PageMode.DEPRECATED) { 319 addActivePageLink(target, contents.deprecatedLabel, 320 configuration.conditionalPages.contains( 321 HtmlConfiguration.ConditionalPage.DEPRECATED)); 322 } else { 323 addDeprecatedLink(target); 324 } 325 if (documentedPage == PageMode.INDEX) { 326 addActivePageLink(target, contents.indexLabel, 327 options.createIndex()); 328 } else { 329 addIndexLink(target); 330 } 331 if (documentedPage == PageMode.HELP) { 332 addActivePageLink(target, contents.helpLabel, 333 !options.noHelp()); 334 } else { 335 addHelpLink(target); 336 } 337 break; 338 case ALL_CLASSES: 339 case ALL_PACKAGES: 340 case CONSTANT_VALUES: 341 case EXTERNAL_SPECS: 342 case SERIALIZED_FORM: 343 case SEARCH: 344 case SYSTEM_PROPERTIES: 345 addOverviewLink(target); 346 addModuleLink(target); 347 addPackageLink(target); 348 addPageLabel(target, contents.classLabel, true); 349 addPageLabel(target, contents.useLabel, options.classUse()); 350 addTreeLink(target); 351 addPreviewLink(target); 352 addNewLink(target); 353 addDeprecatedLink(target); 354 addIndexLink(target); 355 addHelpLink(target); 356 break; 357 case DOC_FILE: 358 addOverviewLink(target); 359 addModuleOfElementLink(target); 360 addItemToList(target, navLinkPackage); 361 addPageLabel(target, contents.classLabel, true); 362 addPageLabel(target, contents.useLabel, options.classUse()); 363 addTreeLink(target); 364 addPreviewLink(target); 365 addNewLink(target); 366 addDeprecatedLink(target); 367 addIndexLink(target); 368 addHelpLink(target); 369 break; 370 default: 371 break; 372 } 373 } 374 375 /** 376 * Adds the summary links to the subnavigation. 377 * 378 * @param target the content to which the subnavigation will be added 379 * @param nested whether to create a flat or nested list 380 */ 381 private void addSummaryLinks(Content target, boolean nested) { 382 switch (documentedPage) { 383 case MODULE, PACKAGE, CLASS, HELP -> { 384 List<? extends Content> listContents = subNavLinks.getSubNavLinks() 385 .stream().map(HtmlTree::LI).toList(); 386 if (!listContents.isEmpty()) { 387 Content label = switch (documentedPage) { 388 case MODULE -> contents.moduleSubNavLabel; 389 case PACKAGE -> contents.packageSubNavLabel; 390 case CLASS -> contents.summaryLabel; 391 case HELP -> contents.helpSubNavLabel; 392 default -> Text.EMPTY; 393 }; 394 if (nested) { 395 target.add(HtmlTree.LI(HtmlTree.P(label)) 396 .add(new HtmlTree(TagName.UL).add(listContents))); 397 } else { 398 target.add(HtmlTree.LI(label).add(Entity.NO_BREAK_SPACE)); 399 addListToNav(listContents, target); 400 } 401 } 402 } 403 } 404 } 405 406 /** 407 * Adds the detail links to subnavigation. 408 * 409 * @param target the content to which the links will be added 410 * @param nested whether to create a flat or nested list 411 */ 412 private void addDetailLinks(Content target, boolean nested) { 413 if (documentedPage == PageMode.CLASS) { 414 List<Content> listContents = new ArrayList<>(); 415 VisibleMemberTable vmt 416 = configuration.getVisibleMemberTable((TypeElement) element); 417 Set<VisibleMemberTable.Kind> detailSet 418 = VisibleMemberTable.Kind.forDetailsOf(element.getKind()); 419 for (VisibleMemberTable.Kind kind : detailSet) { 420 addTypeDetailLink(kind, !vmt.getVisibleMembers(kind).isEmpty(), 421 listContents); 422 } 423 if (!listContents.isEmpty()) { 424 if (nested) { 425 var li = HtmlTree.LI(HtmlTree.P(contents.detailLabel)); 426 li.add(new HtmlTree(TagName.UL).add(listContents)); 427 target.add(li); 428 } else { 429 var li = HtmlTree.LI(contents.detailLabel); 430 li.add(Entity.NO_BREAK_SPACE); 431 target.add(li); 432 addListToNav(listContents, target); 433 } 434 } 435 } 436 } 437 438 /** 439 * Adds the navigation Type detail link. 440 * 441 * @param kind the kind of member being documented 442 * @param link true if the members are listed and need to be linked 443 * @param listContents the list of contents to which the detail will be added. 444 */ 445 protected void addTypeDetailLink(VisibleMemberTable.Kind kind, boolean link, 446 List<Content> listContents) { 447 addContentToList(listContents, switch (kind) { 448 case CONSTRUCTORS -> links.createLink(HtmlIds.CONSTRUCTOR_DETAIL, 449 contents.navConstructor, link); 450 case ENUM_CONSTANTS -> links.createLink(HtmlIds.ENUM_CONSTANT_DETAIL, 451 contents.navEnum, link); 452 case FIELDS -> links.createLink(HtmlIds.FIELD_DETAIL, contents.navField, 453 link); 454 case METHODS -> links.createLink(HtmlIds.METHOD_DETAIL, 455 contents.navMethod, link); 456 case PROPERTIES -> links.createLink(HtmlIds.PROPERTY_DETAIL, 457 contents.navProperty, link); 458 case ANNOTATION_TYPE_MEMBER -> links.createLink( 459 HtmlIds.ANNOTATION_TYPE_ELEMENT_DETAIL, 460 contents.navAnnotationTypeMember, link); 461 default -> Text.EMPTY; 462 }); 463 } 464 465 private void addContentToList(List<Content> listContents, Content source) { 466 listContents.add(HtmlTree.LI(source)); 467 } 468 469 private void addItemToList(Content list, Content item) { 470 list.add(HtmlTree.LI(item)); 471 } 472 473 private void addListToNav(List<? extends Content> listContents, 474 Content target) { 475 int count = 0; 476 for (Content liContent : listContents) { 477 if (count < listContents.size() - 1) { 478 liContent.add(Entity.NO_BREAK_SPACE); 479 liContent.add("|"); 480 liContent.add(Entity.NO_BREAK_SPACE); 481 } 482 target.add(liContent); 483 count++; 484 } 485 } 486 487 private void addActivePageLink(Content target, Content label, 488 boolean display) { 489 if (display) { 490 target.add(HtmlTree.LI(HtmlStyle.navBarCell1Rev, label)); 491 } 492 } 493 494 private void addPageLabel(Content target, Content label, boolean display) { 495 if (display) { 496 target.add(HtmlTree.LI(label)); 497 } 498 } 499 500 private void addOverviewLink(Content target) { 501 if (options.createOverview()) { 502 target.add( 503 HtmlTree.LI(links.createLink(pathToRoot.resolve(DocPaths.INDEX), 504 contents.overviewLabel, ""))); 505 } 506 } 507 508 private void addModuleLink(Content target) { 509 if (configuration.showModules) { 510 if (configuration.modules.size() == 1) { 511 ModuleElement mdle = configuration.modules.first(); 512 boolean included = configuration.utils.isIncluded(mdle); 513 target.add(HtmlTree.LI((included) 514 ? links.createLink( 515 pathToRoot.resolve( 516 configuration.docPaths.moduleSummary(mdle)), 517 contents.moduleLabel, "") 518 : contents.moduleLabel)); 519 } else if (!configuration.modules.isEmpty()) { 520 addPageLabel(target, contents.moduleLabel, true); 521 } 522 } 523 } 524 525 private void addModuleOfElementLink(Content target) { 526 if (configuration.showModules) { 527 target.add(HtmlTree.LI(navLinkModule)); 528 } 529 } 530 531 private void addPackageLink(Content target) { 532 if (configuration.packages.size() == 1) { 533 PackageElement packageElement = configuration.packages.first(); 534 boolean included = packageElement != null 535 && configuration.utils.isIncluded(packageElement); 536 if (!included) { 537 for (PackageElement p : configuration.packages) { 538 if (p.equals(packageElement)) { 539 included = true; 540 break; 541 } 542 } 543 } 544 if (included || packageElement == null) { 545 target.add(HtmlTree.LI(links.createLink( 546 pathToRoot.resolve( 547 configuration.docPaths.forPackage(packageElement) 548 .resolve(DocPaths.PACKAGE_SUMMARY)), 549 contents.packageLabel))); 550 } else { 551 DocLink crossPkgLink = configuration.extern.getExternalLink( 552 packageElement, pathToRoot, 553 DocPaths.PACKAGE_SUMMARY.getPath()); 554 if (crossPkgLink != null) { 555 target.add(HtmlTree.LI( 556 links.createLink(crossPkgLink, contents.packageLabel))); 557 } else { 558 target.add(HtmlTree.LI(contents.packageLabel)); 559 } 560 } 561 } else if (!configuration.packages.isEmpty()) { 562 addPageLabel(target, contents.packageLabel, true); 563 } 564 } 565 566 private void addPackageOfElementLink(Content target) { 567 target.add(HtmlTree.LI( 568 links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_SUMMARY), 569 contents.packageLabel))); 570 } 571 572 private void addPackageSummaryLink(Content target) { 573 target.add(HtmlTree.LI( 574 links.createLink(DocPaths.PACKAGE_SUMMARY, contents.packageLabel))); 575 } 576 577 private void addTreeLink(Content target) { 578 if (options.createTree()) { 579 List<PackageElement> packages 580 = new ArrayList<>(configuration.getSpecifiedPackageElements()); 581 DocPath docPath = packages.size() == 1 582 && configuration.getSpecifiedTypeElements().isEmpty() 583 ? pathToRoot.resolve( 584 configuration.docPaths.forPackage(packages.get(0)) 585 .resolve(DocPaths.PACKAGE_TREE)) 586 : pathToRoot.resolve(DocPaths.OVERVIEW_TREE); 587 target.add( 588 HtmlTree.LI(links.createLink(docPath, contents.treeLabel, ""))); 589 } 590 } 591 592 private void addDeprecatedLink(Content target) { 593 if (configuration.conditionalPages 594 .contains(HtmlConfiguration.ConditionalPage.DEPRECATED)) { 595 target.add(HtmlTree.LI( 596 links.createLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST), 597 contents.deprecatedLabel, ""))); 598 } 599 } 600 601 private void addPreviewLink(Content target) { 602 if (configuration.conditionalPages 603 .contains(HtmlConfiguration.ConditionalPage.PREVIEW)) { 604 target.add(HtmlTree 605 .LI(links.createLink(pathToRoot.resolve(DocPaths.PREVIEW_LIST), 606 contents.previewLabel, ""))); 607 } 608 } 609 610 private void addNewLink(Content target) { 611 if (configuration.conditionalPages 612 .contains(HtmlConfiguration.ConditionalPage.NEW)) { 613 target.add(HtmlTree 614 .LI(links.createLink(pathToRoot.resolve(DocPaths.NEW_LIST), 615 contents.newLabel, ""))); 616 } 617 } 618 619 private void addIndexLink(Content target) { 620 if (options.createIndex()) { 621 target.add(HtmlTree.LI(links.createLink(pathToRoot.resolve( 622 (options.splitIndex() 623 ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1)) 624 : DocPaths.INDEX_ALL)), 625 contents.indexLabel, ""))); 626 } 627 } 628 629 private void addHelpLink(Content target) { 630 if (!options.noHelp()) { 631 String helpfile = options.helpFile(); 632 DocPath helpfilenm; 633 if (helpfile.isEmpty()) { 634 helpfilenm = DocPaths.HELP_DOC; 635 } else { 636 DocFile file 637 = DocFile.createFileForInput(configuration, helpfile); 638 helpfilenm = DocPath.create(file.getName()); 639 } 640 target.add(HtmlTree.LI(links.createLink( 641 new DocLink(pathToRoot.resolve(helpfilenm), 642 htmlIds.forPage(documentedPage).name()), 643 contents.helpLabel, ""))); 644 } 645 } 646 647 private void addSearch(Content target) { 648 String reset = "reset"; 649 var inputText = HtmlTree.INPUT("text", HtmlIds.SEARCH_INPUT) 650 .put(HtmlAttr.PLACEHOLDER, searchPlaceholder); 651 var inputReset = HtmlTree.INPUT(reset, HtmlIds.RESET_BUTTON) 652 .put(HtmlAttr.VALUE, reset); 653 var searchDiv = HtmlTree.DIV(HtmlStyle.navListSearch, 654 links.createLink(pathToRoot.resolve(DocPaths.SEARCH_PAGE), 655 searchLabel, "")); 656 searchDiv.add(inputText); 657 searchDiv.add(inputReset); 658 target.add(searchDiv); 659 } 660 661 /** 662 * Returns the navigation content. 663 * 664 * @return the navigation content 665 */ 666 public Content getContent() { 667 if (options.noNavbar()) { 668 return new ContentBuilder(); 669 } 670 var navigationBar = HtmlTree.NAV(); 671 672 var navDiv = new HtmlTree(TagName.DIV); 673 Content skipNavLinks 674 = contents.getContent("doclet.Skip_navigation_links"); 675 String toggleNavLinks = configuration.getDocResources() 676 .getText("doclet.Toggle_navigation_links"); 677 navigationBar.add(MarkerComments.START_OF_TOP_NAVBAR); 678 // The mobile menu button uses three empty spans to produce its animated 679 // icon 680 HtmlTree iconSpan = HtmlTree.SPAN(HtmlStyle.navBarToggleIcon) 681 .add(Entity.NO_BREAK_SPACE); 682 navDiv.setStyle(HtmlStyle.topNav) 683 .setId(HtmlIds.NAVBAR_TOP) 684 .add( 685 new HtmlTree(TagName.BUTTON).setId(HtmlIds.NAVBAR_TOGGLE_BUTTON) 686 .put(HtmlAttr.ARIA_CONTROLS, HtmlIds.NAVBAR_TOP.name()) 687 .put(HtmlAttr.ARIA_EXPANDED, String.valueOf(false)) 688 .put(HtmlAttr.ARIA_LABEL, toggleNavLinks) 689 .add(iconSpan) 690 .add(iconSpan) 691 .add(iconSpan)) 692 .add(HtmlTree.DIV(HtmlStyle.skipNav, 693 links.createLink(HtmlIds.SKIP_NAVBAR_TOP, skipNavLinks, 694 skipNavLinks.toString()))); 695 Content aboutContent = userHeader; 696 boolean addSearch 697 = options.createIndex() && documentedPage != PageMode.SEARCH; 698 699 var aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, aboutContent); 700 navDiv.add(aboutDiv); 701 var navList = new HtmlTree(TagName.UL) 702 .setId(HtmlIds.NAVBAR_TOP_FIRSTROW) 703 .setStyle(HtmlStyle.navList) 704 .put(HtmlAttr.TITLE, rowListTitle); 705 addMainNavLinks(navList); 706 navDiv.add(navList); 707 var ulNavSummaryRight = HtmlTree.UL(HtmlStyle.subNavListSmall); 708 addSummaryLinks(ulNavSummaryRight, true); 709 addDetailLinks(ulNavSummaryRight, true); 710 navDiv.add(ulNavSummaryRight); 711 navigationBar.add(navDiv); 712 713 var subDiv = HtmlTree.DIV(HtmlStyle.subNav); 714 715 var div = new HtmlTree(TagName.DIV).setId(HtmlIds.NAVBAR_SUB_LIST); 716 // Add the summary links if present. 717 var ulNavSummary = HtmlTree.UL(HtmlStyle.subNavList); 718 addSummaryLinks(ulNavSummary, false); 719 div.add(ulNavSummary); 720 // Add the detail links if present. 721 var ulNavDetail = HtmlTree.UL(HtmlStyle.subNavList); 722 addDetailLinks(ulNavDetail, false); 723 div.add(ulNavDetail); 724 subDiv.add(div); 725 726 if (addSearch) { 727 addSearch(subDiv); 728 } 729 navigationBar.add(subDiv); 730 731 navigationBar.add(MarkerComments.END_OF_TOP_NAVBAR); 732 navigationBar.add(HtmlTree.SPAN(HtmlStyle.skipNav) 733 .addUnchecked(Text.EMPTY) 734 .setId(HtmlIds.SKIP_NAVBAR_TOP)); 735 736 return navigationBar; 737 } 738}