aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamal Carvalho <jamal@golang.org>2020-11-18 16:44:02 -0500
committerJamal Carvalho <jamal@golang.org>2020-11-20 17:37:33 +0000
commit4d2f0315fa39052d667a82308a8e315c412e6321 (patch)
tree70441c6ad1c41420aa07b925932fa45aba2e34f2
parentff4efb1a4d232c4ac063ff38f5985661ea97b37e (diff)
downloadgo-x-pkgsite-4d2f0315fa39052d667a82308a8e315c412e6321.tar.xz
content/static: add readme headings to the sidenav
This change adds the readme headings to the outline in the sidenav and unifies the navigation tree into a single accessible structure. Styles within the tree are based on the accessiblity tree structure. This will make it easier to see when updates to the tree are inserted incorrectly because they'll be matched by visual breakages on the page. Sidenav and readme click handlers are updated to ensure that when an outline item is clicked the corresponding content is visible. Change-Id: Ie6062c24f37bec9fffe242aa1398ec815606c613 Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/271319 Trust: Jamal Carvalho <jamal@golang.org> Run-TryBot: Jamal Carvalho <jamal@golang.org> TryBot-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: Julie Qiu <julie@golang.org>
-rw-r--r--content/static/css/unit_details.css1
-rw-r--r--content/static/css/unit_outline.css150
-rw-r--r--content/static/html/doc/outline.tmpl109
-rw-r--r--content/static/html/helpers/_unit_outline.tmpl81
-rw-r--r--content/static/html/pages/unit.tmpl6
-rw-r--r--content/static/html/pages/unit_details.tmpl20
-rw-r--r--content/static/js/sidenav.js41
-rw-r--r--content/static/js/unit.js17
-rw-r--r--internal/godoc/dochtml/dochtml.go3
-rw-r--r--internal/godoc/dochtml/template.go15
-rw-r--r--internal/middleware/secureheaders.go3
11 files changed, 328 insertions, 118 deletions
diff --git a/content/static/css/unit_details.css b/content/static/css/unit_details.css
index 78ae5d56..ec616d14 100644
--- a/content/static/css/unit_details.css
+++ b/content/static/css/unit_details.css
@@ -9,7 +9,6 @@
@import './unit_files.css';
@import './unit_directories.css';
@import './unit_meta.css';
-@import './legacy_unit_outline.css';
.UnitDetails {
column-gap: 2rem;
diff --git a/content/static/css/unit_outline.css b/content/static/css/unit_outline.css
index 71c8a37e..a74a1bb5 100644
--- a/content/static/css/unit_outline.css
+++ b/content/static/css/unit_outline.css
@@ -4,26 +4,11 @@
* license that can be found in the LICENSE file.
*/
+/* TODO(jamal): remove these styles with legacy code. */
.Documentation-index,
-.DocNav,
.DocNav-index {
display: block;
}
-.DocNav {
- max-height: calc(100vh - var(--header-height));
- overflow-x: unset;
- overflow-y: unset;
- padding-top: 0.5rem;
- padding-left: unset;
- position: unset;
- top: unset;
-}
-@media only screen and (min-width: 52rem) {
- .DocNav [role='tree'],
- .DocNav [role='group'] {
- padding: 0;
- }
-}
.UnitOutline {
display: flex;
@@ -32,30 +17,9 @@
position: sticky;
top: 4.5rem;
}
-a.UnitOutline-accordion {
- align-items: center;
- color: var(--gray-2);
- display: flex;
- font-size: 1.125rem;
- font-weight: 500;
- height: 2.5rem;
- padding: 1rem;
-}
-a.UnitOutline-accordion[aria-expanded='true'] {
- background-color: var(--gray-9);
-}
-.UnitOutline-panel {
- padding: 0 18px;
- background-color: white;
- display: block;
- overflow-y: auto;
-}
-.UnitOutline-panel[aria-hidden='true'] {
- display: none;
-}
.UnitOutline-jumpTo {
display: flex;
- margin-bottom: 0.5625rem;
+ margin-bottom: -0.1625rem;
}
.UnitOutline-jumpTo button {
background-color: white;
@@ -77,6 +41,7 @@ a.UnitOutline-accordion[aria-expanded='true'] {
border-radius: 0.5rem;
color: var(--gray-6);
content: 'f';
+ content: 'f' / 'find';
font-size: 0.75rem;
padding: 0.0625rem 0;
position: absolute;
@@ -98,3 +63,112 @@ a.UnitOutline-accordion[aria-expanded='true'] {
.UnitOutline-jumpToInput:disabled {
background-color: var(--gray-9);
}
+.UnitOutline ul[role='tree'],
+.UnitOutline ul[role='treeitem'],
+.UnitOutline ul[role='group'] {
+ list-style: none;
+ padding-left: 0;
+}
+.UnitOutline li:last-of-type {
+ padding-bottom: 0.25rem;
+}
+.UnitOutline [role='treeitem'][aria-expanded='false'] + ul[role='group'] {
+ display: none;
+}
+.UnitOutline [role='treeitem'][aria-expanded='true'] + ul[role='group'] {
+ display: block;
+}
+.UnitOutline [role='treeitem'][aria-level='1'] + ul[role='group'] {
+ max-height: calc(100vh - 20rem);
+ overflow-y: auto;
+ padding: 0.5rem 0.25rem 0 0.25rem;
+}
+.UnitOutline a {
+ color: var(--gray-2);
+ display: block;
+ line-height: 1.5rem;
+ overflow: hidden;
+ padding: 0.125rem 0 0.125rem 1.25rem;
+ position: relative;
+ text-overflow: ellipsis;
+ user-select: none;
+ white-space: nowrap;
+}
+.UnitOutline a:focus,
+.UnitOutline a:hover {
+ outline: transparent;
+ text-decoration: underline;
+}
+.UnitOutline [role='treeitem'][aria-selected='true'] {
+ color: var(--gray-1);
+}
+.UnitOutline [role='treeitem'][aria-selected='true'] {
+ font-weight: 500;
+}
+.UnitOutline [role='treeitem'][aria-level='1'] {
+ display: block;
+ font-size: 1.125rem;
+ font-weight: 500;
+ line-height: 2.5rem;
+ padding: 0 1rem;
+}
+.UnitOutline [role='treeitem'][aria-level='1'][aria-selected='true'],
+.UnitOutline [role='treeitem'][aria-level='1'][aria-expanded='true'] {
+ background-color: var(--gray-9);
+}
+.UnitOutline [role='treeitem'][aria-level='3'][aria-expanded='true'] {
+ margin-bottom: 0.375em;
+}
+.UnitOutline [role='treeitem'][aria-level='2'] {
+ position: relative;
+ margin-bottom: 0.25rem;
+}
+.UnitOutline [role='treeitem'][aria-level='3'] {
+ font-size: 0.875rem;
+ padding-left: 2.5rem;
+}
+.UnitOutline [role='treeitem'][aria-level='4'] {
+ border-left: 0.125rem solid var(--gray-9);
+ font-size: 0.875rem;
+ margin-left: 2.5rem;
+ padding-left: 0.5rem;
+}
+.UnitOutline [role='treeitem'][aria-selected='true'][aria-level='2']:not([aria-expanded])::before,
+.UnitOutline [role='treeitem'][aria-selected='true'][aria-level='3']:not([aria-expanded])::before {
+ border-radius: 50%;
+ background-color: var(--turq-dark);
+ content: '';
+ display: block;
+ height: 0.3125rem;
+ left: 0.4688rem;
+ position: absolute;
+ top: 0.6875rem;
+ width: 0.3125rem;
+}
+.UnitOutline [role='treeitem'][aria-expanded][aria-owns][aria-level='2']::before,
+.UnitOutline [role='treeitem'][aria-expanded][aria-owns][aria-level='3']::before {
+ border-bottom: 0.25rem solid transparent;
+ border-left: 0.25rem solid var(--gray-4);
+ border-right: 0;
+ border-top: 0.25rem solid transparent;
+ content: '';
+ display: block;
+ height: 0;
+ left: 0.5rem;
+ position: absolute;
+ top: 0.625rem;
+ transition: transform 0.1s linear;
+ width: 0;
+}
+.UnitOutline [role='treeitem'][aria-expanded='true'][aria-level='2']::before,
+.UnitOutline [role='treeitem'][aria-expanded='true'][aria-level='3']::before {
+ transform: rotate(90deg);
+}
+.UnitOutline [role='treeitem'][aria-expanded][aria-level='3']:not([empty]):before,
+.UnitOutline [role='treeitem'][aria-selected][aria-level='3']:not([empty]):before {
+ left: 1.5rem;
+ top: 0.75rem;
+}
+.UnitOutline [role='treeitem'][aria-selected='true'][aria-level='4'] {
+ border-left: 0.125rem solid var(--turq-dark);
+}
diff --git a/content/static/html/doc/outline.tmpl b/content/static/html/doc/outline.tmpl
new file mode 100644
index 00000000..f8885945
--- /dev/null
+++ b/content/static/html/doc/outline.tmpl
@@ -0,0 +1,109 @@
+<!--
+ Copyright 2020 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+-->
+<ul role="group" id="doc-outline">
+ {{if or .Doc (index .Examples.Map "")}}
+ <li role="none">
+ <a href="#pkg-overview" role="treeitem" aria-level="2" tabindex="-1">Overview</a>
+ </li>
+ {{end}}
+ {{- if or .Consts .Vars .Funcs .Types -}}
+ <li class="DocNav-overview" role="none">
+ <a href="#pkg-index" role="treeitem" aria-level="2" tabindex="-1" aria-owns="nav-group-index"
+ {{if .Examples.List}} aria-expanded="false"{{end}}>
+ Index
+ </a>
+ {{if .Examples.List}}
+ <ul role="group" id="nav-group-index">
+ <li role="none">
+ <a href="#pkg-examples" role="treeitem" aria-level="3" tabindex="-1">Examples</a>
+ </li>
+ </ul>
+ {{end}}
+ </li>
+ <li class="DocNav-constants" role="none">
+ <a href="#pkg-constants" role="treeitem" aria-level="2" tabindex="-1">Constants</a>
+ </li>
+ <li class="DocNav-variables" role="none">
+ <a href="#pkg-variables" role="treeitem" aria-level="2" tabindex="-1">Variables</a>
+ </li>
+ <li class="DocNav-functions" role="none">
+ <a href="#pkg-functions" role="treeitem" aria-level="2" tabindex="-1" aria-owns="nav-group-functions"
+ {{if gt (len .Funcs) 0}}aria-expanded="false"{{end}}>
+ Functions
+ </a>
+ <ul role="group" id="nav-group-functions">
+ {{range .Funcs}}
+ <li role="none">
+ <a href="#{{.Name}}" role="treeitem" aria-level="3" tabindex="-1"
+ title="{{render_short_synopsis .Decl}}">
+ {{render_short_synopsis .Decl}}
+ </a>
+ </li>
+ {{end}}
+ </ul>
+ </li>
+ <li class="DocNav-types" role="none">
+ <a href="#pkg-types" role="treeitem" aria-level="2" tabindex="-1" aria-owns="nav-group-types"
+ {{if gt (len .Types) 0}}aria-expanded="false"{{end}}>
+ Types
+ </a>
+ <ul role="group" id="nav-group-types">
+ {{range .Types}}
+ {{$tname := .Name}}
+ <li role="none">
+ {{if or .Funcs .Methods}}
+ {{$navgroupname := (printf "nav.group.%s" $tname)}}
+ {{$navgroupid := (safe_id $navgroupname)}}
+ <a href="#{{$tname}}" role="treeitem" aria-expanded="false" aria-level="3" tabindex="-1"
+ data-aria-owns="{{$navgroupid}}">
+ type {{$tname}}
+ </a>
+ <ul role="group" id="{{$navgroupid}}">
+ {{range .Funcs}}
+ <li role="none">
+ <a href="#{{.Name}}" role="treeitem" aria-level="4" tabindex="-1"
+ title="{{render_short_synopsis .Decl}}">
+ {{render_short_synopsis .Decl}}
+ </a>
+ </li>
+ {{end}}
+ {{range .Methods}}
+ <li role="none">
+ <a href="#{{$tname}}.{{.Name}}" role="treeitem" aria-level="4" tabindex="-1"
+ title="{{render_short_synopsis .Decl}}">
+ {{render_short_synopsis .Decl}}
+ </a>
+ </li>
+ {{end}}
+ </ul>
+ {{else}}
+ <a href="#{{$tname}}" role="treeitem" aria-level="3" tabindex="-1">
+ type {{$tname}}
+ </a>
+ {{end}} {{/* if or .Funcs .Methods */}}
+ </li>
+ {{end}} {{/* range .Types */}}
+ </ul>
+ </li>
+ {{end}}
+ {{if .Notes}}
+ <li role="none">
+ <a href="#pkg-notes" role="treeitem" aria-expanded="false" aria-level="2" tabindex="-1"
+ aria-owns="nav-group-notes">
+ Notes
+ </a>
+ <ul role="group" id="nav-group-notes">
+ {{range $marker, $item := .Notes}}
+ <li role="none">
+ <a href="#pkg-note-{{$marker}}" role="treeitem" aria-level="3" tabindex="-1">
+ {{(index $.NoteHeaders $marker).Label}}s
+ </a>
+ </li>
+ {{end}}
+ </ul>
+ </li>
+ {{end}}
+</ul>
diff --git a/content/static/html/helpers/_unit_outline.tmpl b/content/static/html/helpers/_unit_outline.tmpl
index 3e873fa0..8a47cc7b 100644
--- a/content/static/html/helpers/_unit_outline.tmpl
+++ b/content/static/html/helpers/_unit_outline.tmpl
@@ -5,47 +5,56 @@
-->
{{define "unit_outline"}}
- <div class="UnitOutline js-accordion">
+ <div class="UnitOutline">
<div class="UnitOutline-jumpTo">
<button class="UnitOutline-jumpToInput js-jumpToInput">
Jump to ...
</button>
</div>
- {{if .Readme.String}}
- <a href="?readme=expanded#section-readme" class="UnitOutline-accordion js-accordionTrigger js-readmeExpand"
- role="button" aria-expanded="false" aria-controls="readme-panel" id="readme-accordion">
- README
- </a>
- <div class="UnitOutline-panel js-accordionPanel"
- id="readme-panel" role="region" aria-labelledby="readme-accordion" aria-hidden="true"></div>
- {{end}}
- {{if .IsPackage}}
- <a class="UnitOutline-accordion js-accordionTrigger" href="#section-documentation"
- role="button" aria-expanded="false" aria-controls="outline-panel" id="outline-accordion">
- Documentation
- </a>
- <div class="UnitOutline-panel js-accordionPanel"
- id="outline-panel" role="region" aria-labelledby="outline-accordion" aria-hidden="true">
- <div class="Documentation">
+ <ul class="js-tree" role="tree" aria-label="Outline">
+ {{if .Readme.String}}
+ <li role="none" class="js-readmeOutline">
+ <a href="#section-readme" role="treeitem" aria-expanded="false" aria-selected="false"
+ aria-level="1" aria-owns="readme-outline" tabindex="0">
+ README
+ </a>
+ <ul role="group" id="readme-outline">
+ {{range .ReadmeOutline}}
+ <li role="none">
+ <a href="#{{.ID}}" role="treeitem" aria-selected="false" aria-level="2"
+ tabindex="-1">
+ {{.Text}}
+ </a>
+ </li>
+ {{end}}
+ </ul>
+ </li>
+ {{end}}
+ {{if .IsPackage}}
+ <li role="none">
+ <a href="#section-documentation" role="treeitem" aria-expanded="false" aria-level="1"
+ aria-selected="false"aria-owns="doc-outline" tabindex="-1">
+ Documentation
+ </a>
{{.DocOutline}}
- </div>
- </div>
- {{end}}
- {{if .SourceFiles}}
- <a class="UnitOutline-accordion js-accordionTrigger" href="#section-sourcefiles"
- role="button" aria-expanded="false" aria-controls="files-panel" id="files-accordion">
- Source Files
- </a>
- <div class="UnitOutline-panel js-accordionPanel"
- id="files-panel" role="region" aria-labelledby="files-accordion" aria-hidden="true"></div>
- {{end}}
- {{if (or .Subdirectories .NestedModules)}}
- <a class="UnitOutline-accordion js-accordionTrigger" href="#section-directories"
- role="button" aria-expanded="false" aria-controls="directories-panel" id="directories-accordion">
- Directories
- </a>
- <div class="UnitOutline-panel js-accordionPanel"
- id="directories-panel" role="region" aria-labelledby="directories-accordion" aria-hidden="true"></div>
- {{end}}
+ </li>
+ {{end}}
+ {{if .SourceFiles}}
+ <li role="none">
+ <a href="#section-sourcefiles" role="treeitem" aria-expanded="false"
+ aria-selected="false" aria-level="1" tabindex="-1">
+ Source Files
+ </a>
+ </li>
+ {{end}}
+ {{if (or .Subdirectories .NestedModules)}}
+ <li role="none">
+ <a href="#section-directories" role="treeitem" aria-expanded="false"
+ aria-selected="false" aria-level="1" tabindex="-1">
+ Directories
+ </a>
+ </li>
+ {{end}}
+ </ul>
</div>
{{end}}
diff --git a/content/static/html/pages/unit.tmpl b/content/static/html/pages/unit.tmpl
index 536f4968..18450f10 100644
--- a/content/static/html/pages/unit.tmpl
+++ b/content/static/html/pages/unit.tmpl
@@ -7,7 +7,11 @@
{{define "pre_content"}}
<link href="/static/css/unit.css?version={{.AppVersionLabel}}" rel="stylesheet">
{{block "unit_pre_content" .}}{{end}}
- <link href="/static/css/legacy_unit_outline.css?version={{.AppVersionLabel}}" rel="stylesheet">
+ {{if (.Experiments.IsActive "readme-outline")}}
+ <link href="/static/css/unit_outline.css?version={{.AppVersionLabel}}" rel="stylesheet">
+ {{else}}
+ <link href="/static/css/legacy_unit_outline.css?version={{.AppVersionLabel}}" rel="stylesheet">
+ {{end}}
{{end}}
{{define "main_content"}}
diff --git a/content/static/html/pages/unit_details.tmpl b/content/static/html/pages/unit_details.tmpl
index 71cd63c5..804805c0 100644
--- a/content/static/html/pages/unit_details.tmpl
+++ b/content/static/html/pages/unit_details.tmpl
@@ -14,9 +14,13 @@
<div class="UnitDetails-outline" role="navigation"
aria-label="{{if eq .PageType "std"}}module
{{else}}{{.PageType}}{{end}}details navigation">
- {{block "legacy_unit_outline" .Details}}{{end}}
+ {{if (.Experiments.IsActive "readme-outline")}}
+ {{block "unit_outline" .Details}}{{end}}
+ {{else}}
+ {{block "legacy_unit_outline" .Details}}{{end}}
+ {{end}}
</div>
- <div class="UnitDetails-content" role="main" data-test-id="UnitDetails-content">
+ <div class="UnitDetails-content js-unitDetailsContent" role="main" data-test-id="UnitDetails-content">
{{if .Details.Readme.String}}
{{block "unit_readme" .Details}}{{end}}
{{end}}
@@ -84,7 +88,13 @@
<script>
loadScript("/static/js/playground.min.js", {async: true, defer: true});
</script>
- <script>
- loadScript('/static/js/legacy_sidenav.js', {async: true, defer: true});
- </script>
+ {{if (.Experiments.IsActive "readme-outline")}}
+ <script>
+ loadScript('/static/js/sidenav.js', {type: 'module', async: true, defer: true})
+ </script>
+ {{else}}
+ <script>
+ loadScript('/static/js/legacy_sidenav.js', {async: true, defer: true});
+ </script>
+ {{end}}
{{end}}
diff --git a/content/static/js/sidenav.js b/content/static/js/sidenav.js
index a6355aab..2e3236fd 100644
--- a/content/static/js/sidenav.js
+++ b/content/static/js/sidenav.js
@@ -142,6 +142,10 @@ class DocNavTreeController {
if (!this._selectedEl) {
return;
}
+
+ if (this._selectedEl.getAttribute('aria-level') === '1') {
+ this._selectedEl.setAttribute('aria-expanded', 'true');
+ }
this._selectedEl.setAttribute('aria-selected', 'true');
this.expandAllParents(this._selectedEl);
this.scrollElementIntoView(this._selectedEl);
@@ -211,7 +215,6 @@ class DocNavTreeController {
this.toggleItemExpandedState(el);
}
this.closeInactiveDocNavGroups(el);
- this.closeInactiveDocNavTypeGroups(el);
}
/**
@@ -220,25 +223,9 @@ class DocNavTreeController {
* @private
*/
closeInactiveDocNavGroups(el) {
- if (el.classList.contains('js-docNav')) {
- document.querySelectorAll('.js-docNav').forEach(nav => {
- if (nav.getAttribute('aria-expanded') === 'true' && nav !== el) {
- nav.setAttribute('aria-expanded', 'false');
- }
- });
- this.updateVisibleItems();
- this._focusedIndex = this._visibleItems.indexOf(el);
- }
- }
-
- /**
- * Closes inactive type level nav groups when a new tree item clicked.
- * @param {!Element} el
- * @private
- */
- closeInactiveDocNavTypeGroups(el) {
- if (el.classList.contains('js-docNavType')) {
- document.querySelectorAll('.js-docNavType').forEach(nav => {
+ if (el.hasAttribute('aria-expanded')) {
+ const level = el.getAttribute('aria-level');
+ document.querySelectorAll(`[aria-level="${level}"]`).forEach(nav => {
if (nav.getAttribute('aria-expanded') === 'true' && nav !== el) {
nav.setAttribute('aria-expanded', 'false');
}
@@ -482,7 +469,7 @@ class DocPageController {
* @param {Element} contentEl
*/
constructor(sideNavEl, mobileNavEl, contentEl) {
- if (!sideNavEl || !mobileNavEl || !contentEl) {
+ if (!sideNavEl || !contentEl) {
console.warn('Unable to find all elements needed for navigation');
return;
}
@@ -507,7 +494,9 @@ class DocPageController {
* @type {!MobileNavController}
* @private
*/
- this._mobileNavController = new MobileNavController(mobileNavEl);
+ if (mobileNavEl) {
+ this._mobileNavController = new MobileNavController(mobileNavEl);
+ }
this.updateSelectedIdFromWindowHash();
}
@@ -527,7 +516,9 @@ class DocPageController {
updateSelectedIdFromWindowHash() {
const targetId = this.targetIdFromLocationHash();
this._navController.setSelectedId(targetId);
- this._mobileNavController.setSelectedId(targetId);
+ if (this._mobileNavController) {
+ this._mobileNavController.setSelectedId(targetId);
+ }
if (targetId !== '') {
const targetEl = this._contentEl.querySelector(`[id='${targetId}']`);
if (targetEl) {
@@ -640,7 +631,7 @@ class MobileNavController {
}
new DocPageController(
- document.querySelector('.js-sideNav'),
+ document.querySelector('.js-tree'),
document.querySelector('.js-mobileNav'),
- document.querySelector('.js-docContent')
+ document.querySelector('.js-unitDetailsContent')
);
diff --git a/content/static/js/unit.js b/content/static/js/unit.js
index c26cd137..997c5dfd 100644
--- a/content/static/js/unit.js
+++ b/content/static/js/unit.js
@@ -9,6 +9,7 @@ import { AccordionController } from './accordion.js';
/**
* Instantiates accordion controller for the left sidebar.
+ * Can be removed when readme-outline experiment is turned on.
*/
const accordion = document.querySelector('.js-accordion');
if (accordion) {
@@ -20,9 +21,13 @@ if (accordion) {
*/
const readme = document.querySelector('.js-readme');
const readmeContent = document.querySelector('.js-readmeContent');
+const readmeOutline = document.querySelector('.js-readmeOutline');
const readmeExpand = document.querySelectorAll('.js-readmeExpand');
const readmeCollapse = document.querySelector('.js-readmeCollapse');
-if (readme && readmeContent && readmeExpand.length && readmeCollapse) {
+if (readme && readmeContent && readmeOutline && readmeExpand.length && readmeCollapse) {
+ if (window.location.hash.includes('readme')) {
+ readme.classList.add('UnitReadme--expanded');
+ }
readmeExpand.forEach(el =>
el.addEventListener('click', e => {
e.preventDefault();
@@ -38,17 +43,21 @@ if (readme && readmeContent && readmeExpand.length && readmeCollapse) {
readmeContent.addEventListener('keyup', e => {
readme.classList.add('UnitReadme--expanded');
});
+ readmeContent.addEventListener('click', e => {
+ readme.classList.add('UnitReadme--expanded');
+ });
+ readmeOutline.addEventListener('click', e => {
+ readme.classList.add('UnitReadme--expanded');
+ });
}
/**
* Disable unavailable sections in navigation dropdown on mobile.
*/
const readmeOption = document.querySelector('.js-readmeOption');
-if (!readme) {
+if (readmeOption && !readme) {
readmeOption.setAttribute('disabled', true);
}
-
-const unitFiles = document.querySelector('.js-unitFiles');
const unitDirectories = document.querySelector('.js-unitDirectories');
const directoriesOption = document.querySelector('.js-directoriesOption');
if (!unitDirectories) {
diff --git a/internal/godoc/dochtml/dochtml.go b/internal/godoc/dochtml/dochtml.go
index eecf5951..fa4d887f 100644
--- a/internal/godoc/dochtml/dochtml.go
+++ b/internal/godoc/dochtml/dochtml.go
@@ -147,6 +147,9 @@ func RenderParts(ctx context.Context, fset *token.FileSet, p *doc.Package, opt R
body = exec("body.tmpl")
outline = exec("sidenav.tmpl")
+ if experiment.IsActive(ctx, internal.ExperimentReadmeOutline) {
+ outline = exec("outline.tmpl")
+ }
mobileOutline = exec("sidenav-mobile.tmpl")
if err != nil {
return safehtml.HTML{}, safehtml.HTML{}, safehtml.HTML{}, err
diff --git a/internal/godoc/dochtml/template.go b/internal/godoc/dochtml/template.go
index 6e79ea80..c24af9e1 100644
--- a/internal/godoc/dochtml/template.go
+++ b/internal/godoc/dochtml/template.go
@@ -25,19 +25,20 @@ var (
func LoadTemplates(dir template.TrustedSource) {
loadOnce.Do(func() {
join := template.TrustedSourceJoin
- test := template.TrustedSourceFromConstant
+ tc := template.TrustedSourceFromConstant
- example := join(dir, test("example.tmpl"))
+ example := join(dir, tc("example.tmpl"))
legacyTemplate = template.Must(template.New("legacy.tmpl").
Funcs(tmpl).
- ParseFilesFromTrustedSources(join(dir, test("legacy.tmpl")), example))
+ ParseFilesFromTrustedSources(join(dir, tc("legacy.tmpl")), example))
unitTemplate = template.Must(template.New("unit.tmpl").
Funcs(tmpl).
ParseFilesFromTrustedSources(
- join(dir, test("unit.tmpl")),
- join(dir, test("sidenav.tmpl")),
- join(dir, test("sidenav-mobile.tmpl")),
- join(dir, test("body.tmpl")),
+ join(dir, tc("unit.tmpl")),
+ join(dir, tc("outline.tmpl")),
+ join(dir, tc("sidenav.tmpl")),
+ join(dir, tc("sidenav-mobile.tmpl")),
+ join(dir, tc("body.tmpl")),
example))
})
}
diff --git a/internal/middleware/secureheaders.go b/internal/middleware/secureheaders.go
index cac3ddc1..c36a2747 100644
--- a/internal/middleware/secureheaders.go
+++ b/internal/middleware/secureheaders.go
@@ -33,7 +33,8 @@ var scriptHashes = []string{
// From content/static/html/pages/unit_details.tmpl
"'sha256-CFun5NgnYeEpye8qcbQPq5Ycwavi4IXuZiIzSMNqRUw='",
"'sha256-IHdniK/yZ8URNA2OYbc4R7BssOAe3/dFrSQW7PxEEfM='",
- "'sha256-n5SNZQqoMuOrVKSN3pszZlsWNIrr5HaLOezim/jDLuk='",
+ "'sha256-5ThDRcuVP5qPTu7X6eUxhVjOI8mccPcKwzrWDReVV24='",
+ "'sha256-FZ2G7vOsuMYf1kUB+6G3sewY2N9djmeB36q2IBEdBUE='",
}
// SecureHeaders adds a content-security-policy and other security-related