/ 的 class 属性,
用新加的 langClass 正则限定只能是 "language-X" 形态,防任意
class 注入
- static/frontend/frontend.tmpl:head 末尾加
+
+
{{template "header" .}}
{{template "main" .}}
{{template "footer" .}}
From 6edad4679f0da149927b654928694097e8e33db0 Mon Sep 17 00:00:00 2001
From: Yechi Yang <95576172+NickWilde18@users.noreply.github.com>
Date: Thu, 7 May 2026 15:29:55 +0800
Subject: [PATCH 05/26] feat(p0b): Dockerfile for self-hosted gogodocs
container
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
cmd/pkgsite local mode 跑 docker container 用:
- multi-stage build:golang:1.24 编 cmd/pkgsite 二进制,stage 2 复用
golang:1.24 base(不能用 alpine——local mode 走 go/packages.Load,
container 必须自带 Go toolchain 调 `go list` 解析 module 依赖)
- ARG GOPROXY 默认 goproxy.cn,build / runtime 都生效——内网 / 国内
网络环境的常态
- /repos 约定 mount 目录,docker-compose 把每个 Go module 仓库挂进
这个路径下;容器主进程是 pkgsite,命令行参数指定 base-path /
show-unexported / -http 端口 / mount 进来的 module path
- ENTRYPOINT pkgsite + CMD -h:默认行为是打 usage(防止误启动空容器
hang);docker-compose 通过 command: 覆盖
下一步:Chat 仓库 docker-compose.dev.yml 加 gogodocs service,
mount 仓库,base-path=/gogodocs。
---
Dockerfile | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Dockerfile
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 000000000..8a9282a67
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,43 @@
+# GoGoDocs(fork from golang/pkgsite)容器镜像。
+#
+# 目标场景:内网部署 cmd/pkgsite local mode 服务多个 mount 进来的 Go module
+# 仓库(不走上游 cmd/frontend + worker + Postgres 的全套,省一个数量级运维)。
+#
+# 不能用 alpine 极简 base——cmd/pkgsite 在 local mode 下通过 go/packages.Load
+# 调 `go list` 解析模块依赖,container 必须自带 Go toolchain。同 base image
+# 用 golang:1.24 既 build 又 run,stage 1 复制二进制到 stage 2 也只是少几 MB
+# 收益不显著。
+#
+# GOPROXY 默认走 goproxy.cn 应对国内网络环境;改 build arg / env 可换走
+# 公司内网 Athens 之类。
+
+FROM golang:1.24 AS builder
+WORKDIR /src
+
+# go.mod / go.sum 单独 COPY 让 dep 下载层可缓存(跟随 source 改动)
+COPY go.mod go.sum ./
+ARG GOPROXY=https://goproxy.cn,https://proxy.golang.org,direct
+ENV GOPROXY=${GOPROXY}
+RUN go mod download
+
+COPY . .
+RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /pkgsite ./cmd/pkgsite
+
+FROM golang:1.24
+LABEL org.opencontainers.image.source="https://github.com/NickWilde18/gogodocs"
+LABEL org.opencontainers.image.description="Self-hosted godoc browser (pkgsite fork) with base-path support"
+
+COPY --from=builder /pkgsite /usr/local/bin/pkgsite
+
+# runtime 也需要 GOPROXY 给 go/packages 拉依赖(即便 mount 进来的仓库是 vendor 模式)
+ARG GOPROXY=https://goproxy.cn,https://proxy.golang.org,direct
+ENV GOPROXY=${GOPROXY}
+
+# /repos 是约定的 mount 目录,docker-compose 把每个 Go module 仓库挂进来
+WORKDIR /repos
+
+EXPOSE 8080
+
+# 默认参数让 -h 能直接看 usage;docker-compose 通过 command: 覆盖
+ENTRYPOINT ["pkgsite"]
+CMD ["-h"]
From 6b246791eb15e880e384dbadbd55c11017cbe3ff Mon Sep 17 00:00:00 2001
From: Yechi Yang <95576172+NickWilde18@users.noreply.github.com>
Date: Thu, 7 May 2026 16:04:12 +0800
Subject: [PATCH 06/26] =?UTF-8?q?fix(base-path):=20patch=20ConstructUnitUR?=
=?UTF-8?q?L=20+=20=E5=8D=95=E5=BC=95=E5=8F=B7=20loadScript=20=E6=BC=8F?=
=?UTF-8?q?=E7=BD=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
P1 smoke test 没覆盖到 module overview / unit detail 页的子目录链接,
用户在浏览器实测时发现 chat.cuhksz module 页只显示 api / manifest 两个
目录(internal 被 pkg.go.dev 默认 "Show internal" toggle 隐藏),
点子目录链接还会跳出 base path 外 404——两个独立 bug:
1. internal/frontend/versions/versions.go: ConstructUnitURL 是 pkgsite
内部所有 unit/package/module 详情页链接的核心 URL builder(subdir
列表 / search / breadcrumb 都走它),它生成的绝对路径必须带 base
path 前缀。加包级 var BasePath,cmd/pkgsite/main.go 跟 godoc.IncludeUnexported
同模式设置——pkgsite 单进程一种行为,不必加新参数让上百 caller 都改
2. unit.tmpl / unit/main/main.tmpl / search/search.tmpl 三处
`loadScript('/static/...')` 用**单引号**,P1 sed 只匹配双引号
loadScript("...") 漏过去。改成 `(document.documentElement.dataset.basePath
|| "") + "/static/..."` runtime 拼前缀(同 frontend.tmpl 内 inline
script 模式)。修不修这个的影响:unit.js / main.js bundle 加载 404 →
main.ts 里 "data-local=true 时 auto-click Show internal toggle 让
internal 目录默认展开" 这段没跑 → 用户感知 internal 目录"不存在"
---
cmd/pkgsite/main.go | 8 ++++++++
internal/frontend/versions/versions.go | 18 +++++++++++++++---
static/frontend/search/search.tmpl | 2 +-
static/frontend/unit/main/main.tmpl | 2 +-
static/frontend/unit/unit.tmpl | 2 +-
5 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/cmd/pkgsite/main.go b/cmd/pkgsite/main.go
index f5139d827..32668a654 100644
--- a/cmd/pkgsite/main.go
+++ b/cmd/pkgsite/main.go
@@ -62,6 +62,7 @@ import (
"golang.org/x/pkgsite/cmd/internal/pkgsite"
"golang.org/x/pkgsite/internal/browser"
+ "golang.org/x/pkgsite/internal/frontend/versions"
"golang.org/x/pkgsite/internal/godoc"
"golang.org/x/pkgsite/internal/log"
"golang.org/x/pkgsite/internal/middleware/timeout"
@@ -113,6 +114,13 @@ func main() {
// 单进程 pkgsite 一种行为,没必要加到 ServerConfig 里再透传一层。
godoc.IncludeUnexported = *showUnexported
+ // versions 包级 BasePath——pkgsite 内部 ConstructUnitURL 是所有 unit /
+ // package / module 详情页链接的核心 URL builder(subdir 列表、search
+ // 结果、breadcrumb 都走它),它生成的绝对 URL 必须带 base path 前缀,
+ // 否则点子目录会跳出 base path 外 404。同 godoc.IncludeUnexported 模式
+ // 用包级 var 而非加 ServerConfig 字段层层透传。
+ versions.BasePath = *basePath
+
serverCfg.UseLocalStdlib = true
serverCfg.GoRepoPath = *goRepoPath
serverCfg.Paths = collectPaths(flag.Args())
diff --git a/internal/frontend/versions/versions.go b/internal/frontend/versions/versions.go
index 2cc83214c..43056e859 100644
--- a/internal/frontend/versions/versions.go
+++ b/internal/frontend/versions/versions.go
@@ -430,16 +430,28 @@ func absoluteTime(date time.Time) string {
return date.In(time.UTC).Format("Jan _2, 2006")
}
+// BasePath 是 fork 加的包级 URL 前缀(如 "/gogodocs"),由 cmd/pkgsite/main.go
+// 在 -base-path flag 处设置。空 = 默认挂根,跟上游零差异。
+//
+// [ConstructUnitURL] 是 pkgsite 内部所有 unit / package / module 详情页链接
+// 的核心 URL builder——unit overview 上的子目录列表 / search 结果 / breadcrumb
+// 各处都通过它生成绝对路径。fork 把整站挂在子路径下时这些路径都得带前缀,
+// 否则点子目录链接会跳出 base path 外 404。
+//
+// 用包级 var 跟 [godoc.IncludeUnexported] 同模式——pkgsite 单进程一种行为,
+// 不必 ConstructUnitURL 加新参数让上百个 caller 都改一遍。
+var BasePath string
+
// ConstructUnitURL returns a URL path that refers to the given unit at the requested
// version. If requestedVersion is "latest", then the resulting path has no
// version; otherwise, it has requestedVersion.
func ConstructUnitURL(fullPath, modulePath, requestedVersion string) string {
if requestedVersion == version.Latest {
- return "/" + fullPath
+ return BasePath + "/" + fullPath
}
v := LinkVersion(modulePath, requestedVersion, requestedVersion)
if fullPath == modulePath || modulePath == stdlib.ModulePath {
- return fmt.Sprintf("/%s@%s", fullPath, v)
+ return fmt.Sprintf("%s/%s@%s", BasePath, fullPath, v)
}
- return fmt.Sprintf("/%s@%s/%s", modulePath, v, strings.TrimPrefix(fullPath, modulePath+"/"))
+ return fmt.Sprintf("%s/%s@%s/%s", BasePath, modulePath, v, strings.TrimPrefix(fullPath, modulePath+"/"))
}
diff --git a/static/frontend/search/search.tmpl b/static/frontend/search/search.tmpl
index 7dc1692b6..8eff9a2c2 100644
--- a/static/frontend/search/search.tmpl
+++ b/static/frontend/search/search.tmpl
@@ -18,7 +18,7 @@
{{define "post-content"}}
{{end}}
diff --git a/static/frontend/unit/main/main.tmpl b/static/frontend/unit/main/main.tmpl
index 0f1ee7881..d0e2ddeff 100644
--- a/static/frontend/unit/main/main.tmpl
+++ b/static/frontend/unit/main/main.tmpl
@@ -82,6 +82,6 @@
{{end}}
diff --git a/static/frontend/unit/unit.tmpl b/static/frontend/unit/unit.tmpl
index 6a250a3d1..8366485a6 100644
--- a/static/frontend/unit/unit.tmpl
+++ b/static/frontend/unit/unit.tmpl
@@ -43,6 +43,6 @@
{{define "post-content"}}
{{block "main-scripts" .}}{{end}}
{{end}}
\ No newline at end of file
From bd298b58a062e6ce248cc4f34e0773a7dbda3af2 Mon Sep 17 00:00:00 2001
From: Yechi Yang <95576172+NickWilde18@users.noreply.github.com>
Date: Thu, 7 May 2026 16:16:55 +0800
Subject: [PATCH 07/26] feat(dochtml): minimal markdown ext for doc comments
(inline code / bold / mermaid)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
go/doc/comment parser 不识别 markdown 反引号 / **bold** / fenced code,
但用户写 doc.go 时这些 markdown 风格已经形成习惯(毕竟 .md 写得多)。
渲染产物里 raw \` 和 ** 字面输出体验差,mermaid 图块也没办法变 fenced
code class 让客户端 mermaid.js 渲。
新增 internal/godoc/dochtml/internal/render/markdown_ext.go:
post-process 渲染好的 HTML 加三条 inline 转换:
- \`text\` → text
- **text** → text
- \`\`\`mermaid\\n...\`\`\` → ...
让 frontend.tmpl 里的 mermaid lazy-load CDN 脚本能识别并渲
实现:walkOutsidePre 把 HTML 切成 内 / 外两类 segment, 内
原样保留——godoc 把 markdown 4 空格缩进 code block 渲染成 ,
里面字符按字面(如 Go struct tag literal `json:"..."` 保持不动)。
设计选型:post-process HTML 比 fork go/doc/comment parser 干净——
保留 godoc 原生 [Symbol] cross-reference / heading-id / 链接提取等
功能不变,只在表层加几条 inline 转换。代价是 regex on HTML 不优雅,
但 godoc 渲染的 HTML 结构有限, 边界清晰,实测没遇到 corner case。
linkify.go formatDocHTML 在最后调一次 applyDocMarkdownExt 包装。
Smoke test (/gogodocs/chat.cuhksz/internal/service/im/weixin):
- : 40 个,含 wx:monitor:lease:{upn} 等用户报告的
反引号字面量
- : 38 个,含 不同 binding 等 bold
- language-mermaid: 2 个——doc.go 里两张 mermaid 时序图都被识别,
浏览器侧 mermaid.js 渲成 SVG
---
.../godoc/dochtml/internal/render/linkify.go | 4 +-
.../dochtml/internal/render/markdown_ext.go | 87 +++++++++++++++++++
2 files changed, 90 insertions(+), 1 deletion(-)
create mode 100644 internal/godoc/dochtml/internal/render/markdown_ext.go
diff --git a/internal/godoc/dochtml/internal/render/linkify.go b/internal/godoc/dochtml/internal/render/linkify.go
index 2cbcf41a8..86496ee2d 100644
--- a/internal/godoc/dochtml/internal/render/linkify.go
+++ b/internal/godoc/dochtml/internal/render/linkify.go
@@ -129,7 +129,9 @@ func (r *Renderer) formatDocHTML(text string, decl ast.Decl, extractLinks bool)
if len(hscope.headings) > 0 {
h = safe.HTMLConcat(ExecuteToHTML(tocTemplate, hscope.headings), h)
}
- return h
+ // fork:在 godoc 渲染产物上加最小 markdown 风格 inline 修饰
+ // (`code` / **bold** / mermaid fence)。详见 [applyDocMarkdownExt]。
+ return applyDocMarkdownExt(h)
}
// removeLinks removes the "Links" section from doc.
diff --git a/internal/godoc/dochtml/internal/render/markdown_ext.go b/internal/godoc/dochtml/internal/render/markdown_ext.go
new file mode 100644
index 000000000..d45b73bc9
--- /dev/null
+++ b/internal/godoc/dochtml/internal/render/markdown_ext.go
@@ -0,0 +1,87 @@
+// Copyright 2026 Yechi Yang. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file of the upstream pkgsite.
+
+package render
+
+import (
+ "regexp"
+ "strings"
+
+ "github.com/google/safehtml"
+ "github.com/google/safehtml/uncheckedconversions"
+)
+
+// applyDocMarkdownExt 给 godoc 渲染产物加最小的 markdown 风格 inline 修饰。
+//
+// 背景:godoc 注释走 go/doc/comment parser,不识别 markdown 的反引号
+// inline code / **bold** / fenced code blocks——这些会被原样输出成字面文本。
+// 但用户写 doc.go 时这些 markdown 风格已经形成习惯(毕竟 .md 写得多),
+// 渲染产物里看到 `` `xxx` `` 和 `**bold**` raw text 体验差。
+//
+// 这层 post-process 把渲染好的 HTML 二次扫描加修饰:
+// - `` `text` `` → text
+// - **text** → text
+// - ```mermaid\n...``` → ...
+// 让客户端 mermaid.js 能识别并渲染时序图(frontend.tmpl 里有 lazy-load
+// mermaid CDN 的逻辑,scan 选择器是 code.language-mermaid)
+//
+// 顺序:先处理 mermaid(在 内),再 walkOutsidePre 在 块外面
+// 做 inline 修饰——避免改到 preformatted code 内的字面字符(用户在缩进
+// 4 空格 code block 里写的反引号是真的反引号字面,不是 inline code)。
+//
+// 设计选型:post-process HTML 比 fork go/doc/comment parser 干净——保留
+// godoc 原生的 [Symbol] cross-reference / heading-id / 链接提取等功能不变,
+// 只在表层加几条 inline 转换。代价是 regex on HTML 不优雅,但 godoc 渲染
+// 的 HTML 结构有限制, 边界清晰,实测没遇到 corner case。
+func applyDocMarkdownExt(h safehtml.HTML) safehtml.HTML {
+ s := h.String()
+ s = mermaidPreRe.ReplaceAllString(s, `$1 `)
+ s = walkOutsidePre(s, func(seg string) string {
+ // 顺序:bold 先于 backtick——`**code**` 先匹配粗体再匹配反引号;
+ // 否则反引号匹配会把 ** 包进 code 里破坏。
+ seg = boldRe.ReplaceAllString(seg, "$1 ")
+ seg = backtickRe.ReplaceAllString(seg, "$1")
+ return seg
+ })
+ return uncheckedconversions.HTMLFromStringKnownToSatisfyTypeContract(s)
+}
+
+var (
+ // 反引号 inline code——不跨行(避免 multi-paragraph 误捕、避免与 ``` 围栏
+ // 冲突),允许内容含其他字符但不能再含反引号。
+ backtickRe = regexp.MustCompile("`([^`\n]+)`")
+
+ // **bold**——不跨行;内容不能含 *,避免吃掉相邻 ** 标记。
+ boldRe = regexp.MustCompile(`\*\*([^*\n]+)\*\*`)
+
+ // 内首行 ```mermaid 起头的围栏块——godoc 把 fenced 当 raw text 渲染
+ // 进 ,我们补上 。`(?s)` 让 . 匹配换行。
+ // 容许尾部 ``` 缺失或带空白(godoc preformatted 块包内时尾部 ``` 可能被
+ // 当下一个段落渲染分裂——简化匹配到第一个 闭合)。
+ mermaidPreRe = regexp.MustCompile("(?s)(?:\\s*\n)*```mermaid\\s*\n(.+?)(?:\\s*```\\s*)? ")
+)
+
+// walkOutsidePre 把 html 切成 ... 内 / 外两类 segment,对外面 segment
+// 调用 fn 转换, 内原样保留——godoc 把 markdown 4 空格缩进 code block
+// 渲染成 ,这里面字符按字面,不该被 inline 替换误改。
+func walkOutsidePre(html string, fn func(string) string) string {
+ var out strings.Builder
+ for {
+ idx := strings.Index(html, "")
+ if idx < 0 {
+ out.WriteString(fn(html))
+ return out.String()
+ }
+ out.WriteString(fn(html[:idx]))
+ end := strings.Index(html[idx:], " ")
+ if end < 0 {
+ // 残缺 HTML——直接保留剩余部分不再处理
+ out.WriteString(html[idx:])
+ return out.String()
+ }
+ end += len(" ")
+ out.WriteString(html[idx : idx+end])
+ html = html[idx+end:]
+ }
+}
From e7cf7de9908e97aefc9c231854af64b8aee27f00 Mon Sep 17 00:00:00 2001
From: Yechi Yang <95576172+NickWilde18@users.noreply.github.com>
Date: Thu, 7 May 2026 16:44:48 +0800
Subject: [PATCH 08/26] =?UTF-8?q?fix:=20-show-unexported=20=E7=9C=9F?=
=?UTF-8?q?=E7=94=9F=E6=95=88=20+=20view=20source=20=E5=B8=A6=20base-path?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
两个 bug 一起修:
1. -show-unexported 实际没效果——godoc.IncludeUnexported=true 只让
doc.NewFromFiles 用 doc.AllDecls,但 fetchdatasource 在喂给它之前先
调 godoc.Package.AddFile(removeNodes=true) 在 AST 阶段就剥光未导出
FuncDecl,doc.NewFromFiles 看到的 AST 已经被剔光 → AllDecls 救不回。
修:internal/fetch/load.go 在 godoc.IncludeUnexported=true 时也把
removeNodes 设 false,跟 stdlib builtin 特例同模式保留全部 nodes。
smoke:weixin 包页面 dispatchMessage / authedClient / buildHelpText
等私有函数现作为 data-kind="function" declaration 渲染,不再只是
raw text 引用。
2. view source 链接没带 /gogodocs/ 前缀——cmd/pkgsite local mode 下
source.Info 模板生成 "/files/{path}" 让 file mux serve 源码(不
拷代码到 pod,直接从 mount 进来的目录读),但这个 URL 没经过
ConstructUnitURL 这条已 patched 的路径。修:godoc 加 BasePath
包级 var(同 IncludeUnexported 模式),renderOptions 里加 localPrefix
闭包识别 "/files/" 起头的 local URL 前置 BasePath。GitHub 远程 URL
(http:// 起头)不受影响,跟上游一致。
smoke:view source URL 现是 "/gogodocs/files/.../poll_loop.go" 且 HTTP 200
能正常 serve 源码内容。
---
cmd/pkgsite/main.go | 3 +++
internal/fetch/load.go | 7 +++++++
internal/godoc/render.go | 22 ++++++++++++++++++++--
3 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/cmd/pkgsite/main.go b/cmd/pkgsite/main.go
index 32668a654..d24544312 100644
--- a/cmd/pkgsite/main.go
+++ b/cmd/pkgsite/main.go
@@ -113,6 +113,9 @@ func main() {
// 全局开关——godoc.DocPackage 读包级 var 决定是否传 doc.AllDecls。
// 单进程 pkgsite 一种行为,没必要加到 ServerConfig 里再透传一层。
godoc.IncludeUnexported = *showUnexported
+ // view source / file link 在 local mode 走 "/files/..." 路径——base path
+ // 挂子路径时 godoc.renderOptions 的 localPrefix 闭包读这个 var 加前缀。
+ godoc.BasePath = *basePath
// versions 包级 BasePath——pkgsite 内部 ConstructUnitURL 是所有 unit /
// package / module 详情页链接的核心 URL builder(subdir 列表、search
diff --git a/internal/fetch/load.go b/internal/fetch/load.go
index e8f03316c..5fede8539 100644
--- a/internal/fetch/load.go
+++ b/internal/fetch/load.go
@@ -303,6 +303,13 @@ func loadPackageForBuildContext(ctx context.Context, files map[string][]byte, in
if modulePath == stdlib.ModulePath && innerPath == "builtin" {
removeNodes = false
}
+ // fork:-show-unexported flag 设全局 godoc.IncludeUnexported=true
+ // 时,AST 阶段也保留未导出 FuncDecl(默认 [removeUnusedASTNodes]
+ // 整个剥掉),后续 [DocPackage] 才有 nodes 可读 + doc.AllDecls 才生效。
+ // 否则 doc.AllDecls 在 AST 已经被剔光的输入上无效。
+ if godoc.IncludeUnexported {
+ removeNodes = false
+ }
docPkg.AddFile(pf, removeNodes)
}
diff --git a/internal/godoc/render.go b/internal/godoc/render.go
index 7355e1251..c509ab3aa 100644
--- a/internal/godoc/render.go
+++ b/internal/godoc/render.go
@@ -54,6 +54,15 @@ var MaxDocumentationHTML = 40 * megabyte
// 透传到 [DocPackage] 调用方(caller 链很深)。
var IncludeUnexported bool
+// BasePath 跟 [IncludeUnexported] 同模式的包级开关——cmd/pkgsite/main.go 设。
+//
+// 用途:cmd/pkgsite local mode 下,[Renderer] 生成 view source / file link 时
+// source.Info 走的是 `/files/{path}` 模板,不带 fork 站点子路径。挂
+// -base-path=/gogodocs 时这些链接得变成 `/gogodocs/files/{path}` 才能正确路由
+// 到 file mux。在 [renderOptions] 的 fileLinkFunc / sourceLinkFunc 里识别 local
+// 模式(URL 以 "/files/" 起头)并 prefix。
+var BasePath string
+
// DocInfo returns information extracted from the package's documentation.
// This destroys p's AST; do not call any methods of p after it returns.
func (p *Package) DocInfo(ctx context.Context, innerPath string, sourceInfo *source.Info, modInfo *ModuleInfo) (
@@ -166,6 +175,15 @@ func (p *Package) DocPackage(innerPath string, modInfo *ModuleInfo) (_ *doc.Pack
// renderOptions returns a RenderOptions for p.
func (p *Package) renderOptions(innerPath string, sourceInfo *source.Info, modInfo *ModuleInfo,
nameToVersion map[string]string, bc internal.BuildContext) dochtml.RenderOptions {
+ // localPrefix wrap:cmd/pkgsite local mode 下 source.Info 模板生成 "/files/..."
+ // 路径,挂 -base-path 时要 prefix 才能路由到 file mux;远程 GitHub URL
+ // (以 https:// 起头)不动。空 BasePath 时也 no-op 跟上游一致。
+ localPrefix := func(u string) string {
+ if BasePath != "" && strings.HasPrefix(u, "/files/") {
+ return BasePath + u
+ }
+ return u
+ }
sourceLinkFunc := func(n ast.Node) string {
if sourceInfo == nil {
return ""
@@ -174,13 +192,13 @@ func (p *Package) renderOptions(innerPath string, sourceInfo *source.Info, modIn
if p.Line == 0 { // invalid Position
return ""
}
- return sourceInfo.LineURL(path.Join(innerPath, p.Filename), p.Line)
+ return localPrefix(sourceInfo.LineURL(path.Join(innerPath, p.Filename), p.Line))
}
fileLinkFunc := func(filename string) string {
if sourceInfo == nil {
return ""
}
- return sourceInfo.FileURL(path.Join(innerPath, filename))
+ return localPrefix(sourceInfo.FileURL(path.Join(innerPath, filename)))
}
return dochtml.RenderOptions{
From b1200cf709a08673568eb95067946c7cde87e108 Mon Sep 17 00:00:00 2001
From: Yechi Yang <95576172+NickWilde18@users.noreply.github.com>
Date: Thu, 7 May 2026 17:07:24 +0800
Subject: [PATCH 09/26] =?UTF-8?q?fix:=20bold=20=E8=B7=A8=E8=A1=8C=20+=20?=
=?UTF-8?q?=E5=8A=A0=20unexported=20toggle=20button?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
两个 follow-up bug fix + UX 增强:
1. bold 跨行漏识别:boldRe 旧 pattern \`\`\\*\\*([^*\\n]+)\\*\\*\`\` 排除 \\n
导致跨行 bold 不匹配——godoc 段落渲染保留段内 \\n,bold 写多行
是常见用法(如 weixin/poll_loop.go 里 \`\`**Redis cursor(wx:get_updates_buf:{upn})
只在本批所有 handler 跑完后才推进**\`\` 这种)。改成 \`\`\\*\\*([^*<]{1,500})\\*\\*\`\`
容许 \\n + 用 [^<] 防跨 HTML 段落标签 + 500 字符上限双重防御
贪心跨段。smoke:\`\`Redis cursor(...)只在本批所有 handler
跑完后才推进 \`\` 现正确包标签
2. unexported 符号 toggle(用户报告"私有太多反而拖慢阅读,但有时
要看"):static/frontend/unit/main/main.ts 末尾加 IIFE,按 id
首字母大小写自动给私有 declaration / index 链接的 wrapper 加
.Documentation-unexported class,默认 CSS 隐藏;Index header
旁注入 Show / Hide unexported toggle button,状态写
localStorage 跨页保留。method id "Type.method" 取最后段判私有。
const / var 不动(数量少且 godoc 整组渲染共享 declaration block,
单独 hide 个别名字会破坏视觉)。
---
.../dochtml/internal/render/markdown_ext.go | 7 +-
static/frontend/unit/main/main.js | 4 +-
static/frontend/unit/main/main.js.map | 6 +-
static/frontend/unit/main/main.ts | 76 +++++++++++++++++++
4 files changed, 86 insertions(+), 7 deletions(-)
diff --git a/internal/godoc/dochtml/internal/render/markdown_ext.go b/internal/godoc/dochtml/internal/render/markdown_ext.go
index d45b73bc9..a6ba25a5a 100644
--- a/internal/godoc/dochtml/internal/render/markdown_ext.go
+++ b/internal/godoc/dochtml/internal/render/markdown_ext.go
@@ -52,8 +52,11 @@ var (
// 冲突),允许内容含其他字符但不能再含反引号。
backtickRe = regexp.MustCompile("`([^`\n]+)`")
- // **bold**——不跨行;内容不能含 *,避免吃掉相邻 ** 标记。
- boldRe = regexp.MustCompile(`\*\*([^*\n]+)\*\*`)
+ // **bold**——容许段内跨真实换行(godoc 段落渲染保留 \n,bold 写多行
+ // 是常见用法),但用 `[^<]` 排除 HTML 标签边界 + 500 字符上限防止贪心
+ // 跨段落(godoc 段间用 ,含 < 的字符 class 已经能阻止跨段;
+ // 上限是双重防御,避免 corner case 一路匹到下个 ** 把整页吞了)。
+ boldRe = regexp.MustCompile(`\*\*([^*<]{1,500})\*\*`)
//
内首行 ```mermaid 起头的围栏块——godoc 把 fenced 当 raw text 渲染
// 进 ,我们补上 。`(?s)` 让 . 匹配换行。
diff --git a/static/frontend/unit/main/main.js b/static/frontend/unit/main/main.js
index 29f7e656a..67dc3cbe3 100644
--- a/static/frontend/unit/main/main.js
+++ b/static/frontend/unit/main/main.js
@@ -1,9 +1,9 @@
-function H(){var l;return(l=document.documentElement.dataset.basePath)!=null?l:""}function p(l){return l.startsWith("/")?H()+l:l}var d={PLAY_HREF:".js-exampleHref",PLAY_CONTAINER:".js-exampleContainer",EXAMPLE_INPUT:".Documentation-exampleCode",EXAMPLE_OUTPUT:".Documentation-exampleOutput",EXAMPLE_OUTPUT_CONTAINER:".js-exampleOutputContainer",EXAMPLE_ERROR:".Documentation-exampleError",PLAY_BUTTON:".Documentation-examplePlayButton",SHARE_BUTTON:".Documentation-exampleShareButton",FORMAT_BUTTON:".Documentation-exampleFormatButton",RUN_BUTTON:".Documentation-exampleRunButton"},v=class{constructor(e){this.exampleEl=e;var t,i,s,r;this.exampleEl=e,this.anchorEl=e.querySelector("a"),this.errorEl=e.querySelector(d.EXAMPLE_ERROR),this.playButtonEl=e.querySelector(d.PLAY_BUTTON),this.shareButtonEl=e.querySelector(d.SHARE_BUTTON),this.formatButtonEl=e.querySelector(d.FORMAT_BUTTON),this.runButtonEl=e.querySelector(d.RUN_BUTTON),this.inputEl=this.makeTextArea(e.querySelector(d.EXAMPLE_INPUT)),this.outputEl=e.querySelector(d.EXAMPLE_OUTPUT),this.outputContainerEl=e.querySelector(d.EXAMPLE_OUTPUT_CONTAINER),(t=this.playButtonEl)==null||t.addEventListener("click",()=>this.handleShareButtonClick()),(i=this.shareButtonEl)==null||i.addEventListener("click",()=>this.handleShareButtonClick()),(s=this.formatButtonEl)==null||s.addEventListener("click",()=>this.handleFormatButtonClick()),(r=this.runButtonEl)==null||r.addEventListener("click",()=>this.handleRunButtonClick()),this.inputEl&&(this.resize(),this.inputEl.addEventListener("keyup",()=>this.resize()),this.inputEl.addEventListener("keydown",n=>this.onKeydown(n)))}makeTextArea(e){var i,s;let t=document.createElement("textarea");return t.classList.add("Documentation-exampleCode","code"),t.spellcheck=!1,t.value=(i=e==null?void 0:e.textContent)!=null?i:"",(s=e==null?void 0:e.parentElement)==null||s.replaceChild(t,e),t}getAnchorHash(){var e;return(e=this.anchorEl)==null?void 0:e.hash}expand(){this.exampleEl.open=!0}resize(){var e;if((e=this.inputEl)!=null&&e.value){let t=(this.inputEl.value.match(/\n/g)||[]).length;this.inputEl.style.height=`${(20+t*20+12+2)/16}rem`}}onKeydown(e){e.key==="Tab"&&(document.execCommand("insertText",!1," "),e.preventDefault())}setInputText(e){this.inputEl&&(this.inputEl.value=e)}setOutputText(e){this.outputEl&&(this.outputEl.textContent=e),this.outputContainerEl&&(this.outputContainerEl.hidden=!1)}appendToOutputText(e){this.outputEl&&(this.outputEl.textContent+=e),this.outputContainerEl&&(this.outputContainerEl.hidden=!1)}setOutputHTML(e){this.outputEl&&(this.outputEl.innerHTML=e)}setErrorText(e){this.errorEl&&(this.errorEl.textContent=e),this.setOutputText("An error has occurred\u2026")}getCodeWithModFile(){var i,s,r,n;let e=(s=(i=this.inputEl)==null?void 0:i.value)!=null?s:"",t=(n=(r=document.querySelector(".js-playgroundVars"))==null?void 0:r.dataset)!=null?n:{};return t.modulepath!=="std"&&(e=e.concat(`
+function H(){var l;return(l=document.documentElement.dataset.basePath)!=null?l:""}function p(l){return l.startsWith("/")?H()+l:l}var u={PLAY_HREF:".js-exampleHref",PLAY_CONTAINER:".js-exampleContainer",EXAMPLE_INPUT:".Documentation-exampleCode",EXAMPLE_OUTPUT:".Documentation-exampleOutput",EXAMPLE_OUTPUT_CONTAINER:".js-exampleOutputContainer",EXAMPLE_ERROR:".Documentation-exampleError",PLAY_BUTTON:".Documentation-examplePlayButton",SHARE_BUTTON:".Documentation-exampleShareButton",FORMAT_BUTTON:".Documentation-exampleFormatButton",RUN_BUTTON:".Documentation-exampleRunButton"},x=class{constructor(e){this.exampleEl=e;var t,i,s,n;this.exampleEl=e,this.anchorEl=e.querySelector("a"),this.errorEl=e.querySelector(u.EXAMPLE_ERROR),this.playButtonEl=e.querySelector(u.PLAY_BUTTON),this.shareButtonEl=e.querySelector(u.SHARE_BUTTON),this.formatButtonEl=e.querySelector(u.FORMAT_BUTTON),this.runButtonEl=e.querySelector(u.RUN_BUTTON),this.inputEl=this.makeTextArea(e.querySelector(u.EXAMPLE_INPUT)),this.outputEl=e.querySelector(u.EXAMPLE_OUTPUT),this.outputContainerEl=e.querySelector(u.EXAMPLE_OUTPUT_CONTAINER),(t=this.playButtonEl)==null||t.addEventListener("click",()=>this.handleShareButtonClick()),(i=this.shareButtonEl)==null||i.addEventListener("click",()=>this.handleShareButtonClick()),(s=this.formatButtonEl)==null||s.addEventListener("click",()=>this.handleFormatButtonClick()),(n=this.runButtonEl)==null||n.addEventListener("click",()=>this.handleRunButtonClick()),this.inputEl&&(this.resize(),this.inputEl.addEventListener("keyup",()=>this.resize()),this.inputEl.addEventListener("keydown",r=>this.onKeydown(r)))}makeTextArea(e){var i,s;let t=document.createElement("textarea");return t.classList.add("Documentation-exampleCode","code"),t.spellcheck=!1,t.value=(i=e==null?void 0:e.textContent)!=null?i:"",(s=e==null?void 0:e.parentElement)==null||s.replaceChild(t,e),t}getAnchorHash(){var e;return(e=this.anchorEl)==null?void 0:e.hash}expand(){this.exampleEl.open=!0}resize(){var e;if((e=this.inputEl)!=null&&e.value){let t=(this.inputEl.value.match(/\n/g)||[]).length;this.inputEl.style.height=`${(20+t*20+12+2)/16}rem`}}onKeydown(e){e.key==="Tab"&&(document.execCommand("insertText",!1," "),e.preventDefault())}setInputText(e){this.inputEl&&(this.inputEl.value=e)}setOutputText(e){this.outputEl&&(this.outputEl.textContent=e),this.outputContainerEl&&(this.outputContainerEl.hidden=!1)}appendToOutputText(e){this.outputEl&&(this.outputEl.textContent+=e),this.outputContainerEl&&(this.outputContainerEl.hidden=!1)}setOutputHTML(e){this.outputEl&&(this.outputEl.innerHTML=e)}setErrorText(e){this.errorEl&&(this.errorEl.textContent=e),this.setOutputText("An error has occurred\u2026")}getCodeWithModFile(){var i,s,n,r;let e=(s=(i=this.inputEl)==null?void 0:i.value)!=null?s:"",t=(r=(n=document.querySelector(".js-playgroundVars"))==null?void 0:n.dataset)!=null?r:{};return t.modulepath!=="std"&&(e=e.concat(`
-- go.mod --
module play.ground
require ${t.modulepath} ${t.version}
-`)),e}handleShareButtonClick(){let e="https://play.golang.org/p/";this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/share"),{method:"POST",body:this.getCodeWithModFile()}).then(t=>t.text()).then(t=>{let i=e+t;this.setOutputHTML(`${i} `),window.open(i)}).catch(t=>{this.setErrorText(t)})}handleFormatButtonClick(){var t,i;this.setOutputText("Waiting for remote server\u2026");let e=new FormData;e.append("body",(i=(t=this.inputEl)==null?void 0:t.value)!=null?i:""),fetch(p("/play/fmt"),{method:"POST",body:e}).then(s=>s.json()).then(({Body:s,Error:r})=>{this.setOutputText(r||"Done."),s&&(this.setInputText(s),this.resize())}).catch(s=>{this.setErrorText(s)})}handleRunButtonClick(){this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/compile"),{method:"POST",body:JSON.stringify({body:this.getCodeWithModFile(),version:2})}).then(e=>e.json()).then(async({Events:e,Errors:t})=>{this.setOutputText(t||"");for(let i of e||[])this.appendToOutputText(i.Message),await new Promise(s=>setTimeout(s,i.Delay/1e6))}).catch(e=>{this.setErrorText(e)})}};function I(){let l=location.hash.match(/^#(example-.*)$/);if(l){let i=document.getElementById(l[1]);i&&(i.open=!0)}let e=[...document.querySelectorAll(d.PLAY_HREF)],t=i=>e.find(s=>s.hash===i.getAnchorHash());for(let i of document.querySelectorAll(d.PLAY_CONTAINER)){let s=new v(i),r=t(s);r?r.addEventListener("click",()=>{s.expand()}):console.warn("example href not found")}}var f=class{constructor(e){this.el=e;this.el.addEventListener("change",t=>{let i=t.target,s=i.value;i.value.startsWith("/")||(s="/"+s),window.location.href=s})}};function C(l){let e=document.createElement("label");e.classList.add("go-Label"),e.setAttribute("aria-label","Menu");let t=document.createElement("select");t.classList.add("go-Select","js-selectNav"),e.appendChild(t);let i=document.createElement("optgroup");i.label="Outline",t.appendChild(i);let s={},r;for(let n of l.treeitems){if(Number(n.depth)>4)continue;n.groupTreeitem?(r=s[n.groupTreeitem.label],r||(r=s[n.groupTreeitem.label]=document.createElement("optgroup"),r.label=n.groupTreeitem.label,t.appendChild(r))):r=i;let a=document.createElement("option");a.label=n.label,a.textContent=n.label,a.value=n.el.href.replace(window.location.origin,"").replace("/",""),r.appendChild(a)}return l.addObserver(n=>{var c;let a=n.el.hash,u=(c=t.querySelector(`[value$="${a}"]`))==null?void 0:c.value;u&&(t.value=u)},50),e}var E=class{constructor(e){this.el=e;this.handleResize=()=>{this.el.style.setProperty("--js-tree-height","100vh"),this.el.style.setProperty("--js-tree-height",this.el.clientHeight+"px")};this.treeitems=[],this.firstChars=[],this.firstTreeitem=null,this.lastTreeitem=null,this.observerCallbacks=[],this.init()}init(){this.handleResize(),window.addEventListener("resize",this.handleResize),this.findTreeItems(),this.updateVisibleTreeitems(),this.observeTargets(),this.firstTreeitem&&(this.firstTreeitem.el.tabIndex=0)}observeTargets(){this.addObserver(i=>{this.expandTreeitem(i),this.setSelected(i)});let e=new Map,t=new IntersectionObserver(i=>{for(let s of i)e.set(s.target.id,s.isIntersecting||s.intersectionRatio===1);for(let[s,r]of e)if(r){let n=this.treeitems.find(a=>{var u;return(u=a.el)==null?void 0:u.href.endsWith(`#${s}`)});if(n)for(let a of this.observerCallbacks)a(n);break}},{threshold:1,rootMargin:"-60px 0px 0px 0px"});for(let i of this.treeitems.map(s=>s.el.getAttribute("href")))if(i){let s=i.replace(window.location.origin,"").replace("/","").replace("#",""),r=document.getElementById(s);r&&!s.startsWith("example-")&&t.observe(r)}}addObserver(e,t=200){this.observerCallbacks.push(O(e,t))}setFocusToNextItem(e){let t=null;for(let i=e.index+1;i-1;i--){let s=this.treeitems[i];if(s.isVisible){t=s;break}}t&&this.setFocusToItem(t)}setFocusToParentItem(e){e.groupTreeitem&&this.setFocusToItem(e.groupTreeitem)}setFocusToFirstItem(){this.firstTreeitem&&this.setFocusToItem(this.firstTreeitem)}setFocusToLastItem(){this.lastTreeitem&&this.setFocusToItem(this.lastTreeitem)}setSelected(e){var t;for(let i of this.el.querySelectorAll('[aria-expanded="true"]'))i!==e.el&&((t=i.nextElementSibling)!=null&&t.contains(e.el)||i.setAttribute("aria-expanded","false"));for(let i of this.el.querySelectorAll("[aria-selected]"))i!==e.el&&i.setAttribute("aria-selected","false");e.el.setAttribute("aria-selected","true"),this.updateVisibleTreeitems(),this.setFocusToItem(e,!1)}expandTreeitem(e){let t=e;for(;t;)t.isExpandable&&t.el.setAttribute("aria-expanded","true"),t=t.groupTreeitem;this.updateVisibleTreeitems()}expandAllSiblingItems(e){for(let t of this.treeitems)t.groupTreeitem===e.groupTreeitem&&t.isExpandable&&this.expandTreeitem(t)}collapseTreeitem(e){let t=null;e.isExpanded()?t=e:t=e.groupTreeitem,t&&(t.el.setAttribute("aria-expanded","false"),this.updateVisibleTreeitems(),this.setFocusToItem(t))}setFocusByFirstCharacter(e,t){let i,s;t=t.toLowerCase(),i=e.index+1,i===this.treeitems.length&&(i=0),s=this.getIndexFirstChars(i,t),s===-1&&(s=this.getIndexFirstChars(0,t)),s>-1&&this.setFocusToItem(this.treeitems[s])}findTreeItems(){let e=(t,i)=>{let s=i,r=t.firstElementChild;for(;r;)(r.tagName==="A"||r.tagName==="SPAN")&&(s=new x(r,this,i),this.treeitems.push(s),this.firstChars.push(s.label.substring(0,1).toLowerCase())),r.firstElementChild&&e(r,s),r=r.nextElementSibling};e(this.el,null),this.treeitems.map((t,i)=>t.index=i)}updateVisibleTreeitems(){this.firstTreeitem=this.treeitems[0];for(let e of this.treeitems){let t=e.groupTreeitem;for(e.isVisible=!0;t&&t.el!==this.el;)t.isExpanded()||(e.isVisible=!1),t=t.groupTreeitem;e.isVisible&&(this.lastTreeitem=e)}}setFocusToItem(e,t=!0){e.el.tabIndex=0,t&&e.el.focus();for(let i of this.treeitems)i!==e&&(i.el.tabIndex=-1)}getIndexFirstChars(e,t){for(let i=e;i{let s=()=>{t=null,l(...i)};t&&clearTimeout(t),t=setTimeout(s,e)}}var T=class{constructor(e,t){this.table=e;this.toggleAll=t;this.expandAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","true")),this.update()};this.collapseAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","false")),this.update()};this.update=()=>{this.updateVisibleItems(),setTimeout(()=>this.updateGlobalToggle())};this.rows=Array.from(e.querySelectorAll("[data-aria-controls]")),this.toggles=Array.from(this.table.querySelectorAll("[aria-expanded]")),this.setAttributes(),this.attachEventListeners(),this.update()}setAttributes(){for(let e of["data-aria-controls","data-aria-labelledby","data-id"])this.table.querySelectorAll(`[${e}]`).forEach(t=>{var i;t.setAttribute(e.replace("data-",""),(i=t.getAttribute(e))!=null?i:""),t.removeAttribute(e)})}attachEventListeners(){var e;this.rows.forEach(t=>{t.addEventListener("click",i=>{this.handleToggleClick(i)})}),(e=this.toggleAll)==null||e.addEventListener("click",()=>{this.expandAllItems()}),document.addEventListener("keydown",t=>{(t.ctrlKey||t.metaKey)&&t.key==="f"&&this.expandAllItems()})}handleToggleClick(e){let t=e.currentTarget;t!=null&&t.hasAttribute("aria-expanded")||(t=this.table.querySelector(`button[aria-controls="${t==null?void 0:t.getAttribute("aria-controls")}"]`));let i=(t==null?void 0:t.getAttribute("aria-expanded"))==="true";t==null||t.setAttribute("aria-expanded",i?"false":"true"),e.stopPropagation(),this.update()}updateVisibleItems(){this.rows.map(e=>{var s;let t=(e==null?void 0:e.getAttribute("aria-expanded"))==="true",i=(s=e==null?void 0:e.getAttribute("aria-controls"))==null?void 0:s.trimEnd().split(" ");i==null||i.map(r=>{let n=document.getElementById(`${r}`);t?(n==null||n.classList.add("visible"),n==null||n.classList.remove("hidden")):(n==null||n.classList.add("hidden"),n==null||n.classList.remove("visible"))})})}updateGlobalToggle(){if(!this.toggleAll)return;this.rows.some(t=>t.hasAttribute("aria-expanded"))&&(this.toggleAll.style.display="block"),this.toggles.some(t=>t.getAttribute("aria-expanded")==="false")?(this.toggleAll.innerText="Expand all",this.toggleAll.onclick=this.expandAllItems,this.toggleAll.setAttribute("aria-label","Expand all directories"),this.toggleAll.setAttribute("aria-live","polite")):(this.toggleAll.innerText="Collapse all",this.toggleAll.onclick=this.collapseAllItems,this.toggleAll.setAttribute("aria-label","Collapse all directories"),this.toggleAll.setAttribute("aria-live","polite"))}};I();var m=document.querySelector(".js-expandableTable");if(m){let l=new T(m,document.querySelector(".js-expandAllDirectories"));window.location.search.includes("expand-directories")&&l.expandAllItems();let e=document.querySelector(".js-showInternalDirectories");e&&(document.querySelector(".UnitDirectories-internal")&&(e.style.display="block",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-describedby","showInternal-description")),e.addEventListener("click",()=>{m.classList.contains("UnitDirectories-showInternal")?(m.classList.remove("UnitDirectories-showInternal"),e.innerText="Show internal",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","showInternal-description")):(m.classList.add("UnitDirectories-showInternal"),e.innerText="Hide internal",e.setAttribute("aria-label","Hide Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","hideInternal-description"))})),document.querySelector('html[data-local="true"]')&&(e==null||e.click())}var S=document.querySelector(".js-tree");if(S){let l=new E(S),e=C(l),t=document.querySelector(".js-mainNavMobile");t&&t.firstElementChild&&(t==null||t.replaceChild(e,t.firstElementChild)),e.firstElementChild&&new f(e.firstElementChild)}var o=document.querySelector(".js-readme"),g=document.querySelector(".js-readmeContent"),w=document.querySelector(".js-readmeOutline"),b=document.querySelectorAll(".js-readmeExpand"),k=document.querySelector(".js-readmeCollapse"),A=document.querySelector(".DocNavMobile-select");o&&g&&w&&b.length&&k&&(o.clientHeight>320&&(o==null||o.classList.remove("UnitReadme--expanded"),o==null||o.classList.add("UnitReadme--toggle")),window.location.hash.includes("readme")&&h(),A==null||A.addEventListener("change",l=>{l.target.value.startsWith("readme-")&&h()}),b.forEach(l=>l.addEventListener("click",e=>{e.preventDefault(),h(),o.scrollIntoView()})),k.addEventListener("click",l=>{l.preventDefault(),o.classList.remove("UnitReadme--expanded"),b[1]&&b[1].scrollIntoView({block:"center"})}),g.addEventListener("keyup",()=>{h()}),g.addEventListener("click",()=>{h()}),w.addEventListener("click",()=>{h()}),document.addEventListener("keydown",l=>{(l.ctrlKey||l.metaKey)&&l.key==="f"&&h()}));function h(){history.replaceState(null,"",`${location.pathname}${location.search}#section-readme`),o==null||o.classList.add("UnitReadme--expanded")}function M(){var t;if(!location.hash)return;let l=document.getElementById(location.hash.slice(1)),e=(t=l==null?void 0:l.parentElement)==null?void 0:t.parentElement;(e==null?void 0:e.nodeName)==="DETAILS"&&(e.open=!0)}M();window.addEventListener("hashchange",()=>M());document.querySelectorAll(".js-buildContextSelect").forEach(l=>{l.addEventListener("change",e=>{window.location.search=`?GOOS=${e.target.value}`})});
+`)),e}handleShareButtonClick(){let e="https://play.golang.org/p/";this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/share"),{method:"POST",body:this.getCodeWithModFile()}).then(t=>t.text()).then(t=>{let i=e+t;this.setOutputHTML(`${i} `),window.open(i)}).catch(t=>{this.setErrorText(t)})}handleFormatButtonClick(){var t,i;this.setOutputText("Waiting for remote server\u2026");let e=new FormData;e.append("body",(i=(t=this.inputEl)==null?void 0:t.value)!=null?i:""),fetch(p("/play/fmt"),{method:"POST",body:e}).then(s=>s.json()).then(({Body:s,Error:n})=>{this.setOutputText(n||"Done."),s&&(this.setInputText(s),this.resize())}).catch(s=>{this.setErrorText(s)})}handleRunButtonClick(){this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/compile"),{method:"POST",body:JSON.stringify({body:this.getCodeWithModFile(),version:2})}).then(e=>e.json()).then(async({Events:e,Errors:t})=>{this.setOutputText(t||"");for(let i of e||[])this.appendToOutputText(i.Message),await new Promise(s=>setTimeout(s,i.Delay/1e6))}).catch(e=>{this.setErrorText(e)})}};function C(){let l=location.hash.match(/^#(example-.*)$/);if(l){let i=document.getElementById(l[1]);i&&(i.open=!0)}let e=[...document.querySelectorAll(u.PLAY_HREF)],t=i=>e.find(s=>s.hash===i.getAnchorHash());for(let i of document.querySelectorAll(u.PLAY_CONTAINER)){let s=new x(i),n=t(s);n?n.addEventListener("click",()=>{s.expand()}):console.warn("example href not found")}}var f=class{constructor(e){this.el=e;this.el.addEventListener("change",t=>{let i=t.target,s=i.value;i.value.startsWith("/")||(s="/"+s),window.location.href=s})}};function I(l){let e=document.createElement("label");e.classList.add("go-Label"),e.setAttribute("aria-label","Menu");let t=document.createElement("select");t.classList.add("go-Select","js-selectNav"),e.appendChild(t);let i=document.createElement("optgroup");i.label="Outline",t.appendChild(i);let s={},n;for(let r of l.treeitems){if(Number(r.depth)>4)continue;r.groupTreeitem?(n=s[r.groupTreeitem.label],n||(n=s[r.groupTreeitem.label]=document.createElement("optgroup"),n.label=r.groupTreeitem.label,t.appendChild(n))):n=i;let a=document.createElement("option");a.label=r.label,a.textContent=r.label,a.value=r.el.href.replace(window.location.origin,"").replace("/",""),n.appendChild(a)}return l.addObserver(r=>{var h;let a=r.el.hash,d=(h=t.querySelector(`[value$="${a}"]`))==null?void 0:h.value;d&&(t.value=d)},50),e}var E=class{constructor(e){this.el=e;this.handleResize=()=>{this.el.style.setProperty("--js-tree-height","100vh"),this.el.style.setProperty("--js-tree-height",this.el.clientHeight+"px")};this.treeitems=[],this.firstChars=[],this.firstTreeitem=null,this.lastTreeitem=null,this.observerCallbacks=[],this.init()}init(){this.handleResize(),window.addEventListener("resize",this.handleResize),this.findTreeItems(),this.updateVisibleTreeitems(),this.observeTargets(),this.firstTreeitem&&(this.firstTreeitem.el.tabIndex=0)}observeTargets(){this.addObserver(i=>{this.expandTreeitem(i),this.setSelected(i)});let e=new Map,t=new IntersectionObserver(i=>{for(let s of i)e.set(s.target.id,s.isIntersecting||s.intersectionRatio===1);for(let[s,n]of e)if(n){let r=this.treeitems.find(a=>{var d;return(d=a.el)==null?void 0:d.href.endsWith(`#${s}`)});if(r)for(let a of this.observerCallbacks)a(r);break}},{threshold:1,rootMargin:"-60px 0px 0px 0px"});for(let i of this.treeitems.map(s=>s.el.getAttribute("href")))if(i){let s=i.replace(window.location.origin,"").replace("/","").replace("#",""),n=document.getElementById(s);n&&!s.startsWith("example-")&&t.observe(n)}}addObserver(e,t=200){this.observerCallbacks.push(O(e,t))}setFocusToNextItem(e){let t=null;for(let i=e.index+1;i-1;i--){let s=this.treeitems[i];if(s.isVisible){t=s;break}}t&&this.setFocusToItem(t)}setFocusToParentItem(e){e.groupTreeitem&&this.setFocusToItem(e.groupTreeitem)}setFocusToFirstItem(){this.firstTreeitem&&this.setFocusToItem(this.firstTreeitem)}setFocusToLastItem(){this.lastTreeitem&&this.setFocusToItem(this.lastTreeitem)}setSelected(e){var t;for(let i of this.el.querySelectorAll('[aria-expanded="true"]'))i!==e.el&&((t=i.nextElementSibling)!=null&&t.contains(e.el)||i.setAttribute("aria-expanded","false"));for(let i of this.el.querySelectorAll("[aria-selected]"))i!==e.el&&i.setAttribute("aria-selected","false");e.el.setAttribute("aria-selected","true"),this.updateVisibleTreeitems(),this.setFocusToItem(e,!1)}expandTreeitem(e){let t=e;for(;t;)t.isExpandable&&t.el.setAttribute("aria-expanded","true"),t=t.groupTreeitem;this.updateVisibleTreeitems()}expandAllSiblingItems(e){for(let t of this.treeitems)t.groupTreeitem===e.groupTreeitem&&t.isExpandable&&this.expandTreeitem(t)}collapseTreeitem(e){let t=null;e.isExpanded()?t=e:t=e.groupTreeitem,t&&(t.el.setAttribute("aria-expanded","false"),this.updateVisibleTreeitems(),this.setFocusToItem(t))}setFocusByFirstCharacter(e,t){let i,s;t=t.toLowerCase(),i=e.index+1,i===this.treeitems.length&&(i=0),s=this.getIndexFirstChars(i,t),s===-1&&(s=this.getIndexFirstChars(0,t)),s>-1&&this.setFocusToItem(this.treeitems[s])}findTreeItems(){let e=(t,i)=>{let s=i,n=t.firstElementChild;for(;n;)(n.tagName==="A"||n.tagName==="SPAN")&&(s=new g(n,this,i),this.treeitems.push(s),this.firstChars.push(s.label.substring(0,1).toLowerCase())),n.firstElementChild&&e(n,s),n=n.nextElementSibling};e(this.el,null),this.treeitems.map((t,i)=>t.index=i)}updateVisibleTreeitems(){this.firstTreeitem=this.treeitems[0];for(let e of this.treeitems){let t=e.groupTreeitem;for(e.isVisible=!0;t&&t.el!==this.el;)t.isExpanded()||(e.isVisible=!1),t=t.groupTreeitem;e.isVisible&&(this.lastTreeitem=e)}}setFocusToItem(e,t=!0){e.el.tabIndex=0,t&&e.el.focus();for(let i of this.treeitems)i!==e&&(i.el.tabIndex=-1)}getIndexFirstChars(e,t){for(let i=e;i{let s=()=>{t=null,l(...i)};t&&clearTimeout(t),t=setTimeout(s,e)}}var T=class{constructor(e,t){this.table=e;this.toggleAll=t;this.expandAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","true")),this.update()};this.collapseAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","false")),this.update()};this.update=()=>{this.updateVisibleItems(),setTimeout(()=>this.updateGlobalToggle())};this.rows=Array.from(e.querySelectorAll("[data-aria-controls]")),this.toggles=Array.from(this.table.querySelectorAll("[aria-expanded]")),this.setAttributes(),this.attachEventListeners(),this.update()}setAttributes(){for(let e of["data-aria-controls","data-aria-labelledby","data-id"])this.table.querySelectorAll(`[${e}]`).forEach(t=>{var i;t.setAttribute(e.replace("data-",""),(i=t.getAttribute(e))!=null?i:""),t.removeAttribute(e)})}attachEventListeners(){var e;this.rows.forEach(t=>{t.addEventListener("click",i=>{this.handleToggleClick(i)})}),(e=this.toggleAll)==null||e.addEventListener("click",()=>{this.expandAllItems()}),document.addEventListener("keydown",t=>{(t.ctrlKey||t.metaKey)&&t.key==="f"&&this.expandAllItems()})}handleToggleClick(e){let t=e.currentTarget;t!=null&&t.hasAttribute("aria-expanded")||(t=this.table.querySelector(`button[aria-controls="${t==null?void 0:t.getAttribute("aria-controls")}"]`));let i=(t==null?void 0:t.getAttribute("aria-expanded"))==="true";t==null||t.setAttribute("aria-expanded",i?"false":"true"),e.stopPropagation(),this.update()}updateVisibleItems(){this.rows.map(e=>{var s;let t=(e==null?void 0:e.getAttribute("aria-expanded"))==="true",i=(s=e==null?void 0:e.getAttribute("aria-controls"))==null?void 0:s.trimEnd().split(" ");i==null||i.map(n=>{let r=document.getElementById(`${n}`);t?(r==null||r.classList.add("visible"),r==null||r.classList.remove("hidden")):(r==null||r.classList.add("hidden"),r==null||r.classList.remove("visible"))})})}updateGlobalToggle(){if(!this.toggleAll)return;this.rows.some(t=>t.hasAttribute("aria-expanded"))&&(this.toggleAll.style.display="block"),this.toggles.some(t=>t.getAttribute("aria-expanded")==="false")?(this.toggleAll.innerText="Expand all",this.toggleAll.onclick=this.expandAllItems,this.toggleAll.setAttribute("aria-label","Expand all directories"),this.toggleAll.setAttribute("aria-live","polite")):(this.toggleAll.innerText="Collapse all",this.toggleAll.onclick=this.collapseAllItems,this.toggleAll.setAttribute("aria-label","Collapse all directories"),this.toggleAll.setAttribute("aria-live","polite"))}};C();var m=document.querySelector(".js-expandableTable");if(m){let l=new T(m,document.querySelector(".js-expandAllDirectories"));window.location.search.includes("expand-directories")&&l.expandAllItems();let e=document.querySelector(".js-showInternalDirectories");e&&(document.querySelector(".UnitDirectories-internal")&&(e.style.display="block",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-describedby","showInternal-description")),e.addEventListener("click",()=>{m.classList.contains("UnitDirectories-showInternal")?(m.classList.remove("UnitDirectories-showInternal"),e.innerText="Show internal",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","showInternal-description")):(m.classList.add("UnitDirectories-showInternal"),e.innerText="Hide internal",e.setAttribute("aria-label","Hide Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","hideInternal-description"))})),document.querySelector('html[data-local="true"]')&&(e==null||e.click())}var S=document.querySelector(".js-tree");if(S){let l=new E(S),e=I(l),t=document.querySelector(".js-mainNavMobile");t&&t.firstElementChild&&(t==null||t.replaceChild(e,t.firstElementChild)),e.firstElementChild&&new f(e.firstElementChild)}var o=document.querySelector(".js-readme"),v=document.querySelector(".js-readmeContent"),w=document.querySelector(".js-readmeOutline"),b=document.querySelectorAll(".js-readmeExpand"),M=document.querySelector(".js-readmeCollapse"),y=document.querySelector(".DocNavMobile-select");o&&v&&w&&b.length&&M&&(o.clientHeight>320&&(o==null||o.classList.remove("UnitReadme--expanded"),o==null||o.classList.add("UnitReadme--toggle")),window.location.hash.includes("readme")&&c(),y==null||y.addEventListener("change",l=>{l.target.value.startsWith("readme-")&&c()}),b.forEach(l=>l.addEventListener("click",e=>{e.preventDefault(),c(),o.scrollIntoView()})),M.addEventListener("click",l=>{l.preventDefault(),o.classList.remove("UnitReadme--expanded"),b[1]&&b[1].scrollIntoView({block:"center"})}),v.addEventListener("keyup",()=>{c()}),v.addEventListener("click",()=>{c()}),w.addEventListener("click",()=>{c()}),document.addEventListener("keydown",l=>{(l.ctrlKey||l.metaKey)&&l.key==="f"&&c()}));function c(){history.replaceState(null,"",`${location.pathname}${location.search}#section-readme`),o==null||o.classList.add("UnitReadme--expanded")}function k(){var t;if(!location.hash)return;let l=document.getElementById(location.hash.slice(1)),e=(t=l==null?void 0:l.parentElement)==null?void 0:t.parentElement;(e==null?void 0:e.nodeName)==="DETAILS"&&(e.open=!0)}k();window.addEventListener("hashchange",()=>k());document.querySelectorAll(".js-buildContextSelect").forEach(l=>{l.addEventListener("change",e=>{window.location.search=`?GOOS=${e.target.value}`})});(()=>{if(!document.querySelector("h4[data-kind]"))return;let l=r=>{var d;let a=(d=r.split(".").pop())!=null?d:r;return/^[a-z]/.test(a)};document.querySelectorAll("h4[data-kind][id]").forEach(r=>{if(!l(r.id))return;let a=r.closest(".Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod");a==null||a.classList.add("Documentation-unexported")}),document.querySelectorAll('.Documentation-indexFunction a[href^="#"], .Documentation-indexType a[href^="#"], .Documentation-indexTypeFunctions a[href^="#"], .Documentation-indexTypeMethods a[href^="#"]').forEach(r=>{var a;l(r.getAttribute("href").slice(1))&&((a=r.closest("li"))==null||a.classList.add("Documentation-unexported"))});let e=document.createElement("style");e.textContent="body:not(.show-unexported) .Documentation-unexported{display:none}",document.head.appendChild(e);let t=document.querySelector("#pkg-index");if(!t)return;let i=document.createElement("button");i.type="button",i.className="go-Button go-Button--inline",i.style.marginLeft="0.75rem",i.style.fontSize="0.875rem",i.style.verticalAlign="middle";let s="gogodocs:showUnexported",n=r=>{document.body.classList.toggle("show-unexported",r),i.textContent=r?"Hide unexported":"Show unexported";try{localStorage.setItem(s,r?"1":"0")}catch{}};n(localStorage.getItem(s)==="1"),i.addEventListener("click",()=>n(!document.body.classList.contains("show-unexported"))),t.appendChild(i)})();
/**
* @license
* Copyright 2024 The Go Authors. All rights reserved.
diff --git a/static/frontend/unit/main/main.js.map b/static/frontend/unit/main/main.js.map
index f599413c2..154bedf34 100644
--- a/static/frontend/unit/main/main.js.map
+++ b/static/frontend/unit/main/main.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../../shared/base-path/base-path.ts", "../../../shared/playground/playground.ts", "../../../shared/outline/select.ts", "../../../shared/outline/tree.ts", "../../../shared/table/table.ts", "main.ts"],
- "sourcesContent": ["/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/gogodocs \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/gogodocs\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/gogodocs/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/gogodocs/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/*!\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the playground implementation of the documentation\n// page. The playground involves a \"play\" button that allows you to open up\n// a new link to play.golang.org using the example code.\n\n// The CSS is in static/frontend/unit/main/_doc.css\n\nimport { abs } from '../base-path/base-path';\n\n/**\n * CSS classes used by PlaygroundExampleController\n */\nconst PlayExampleClassName = {\n PLAY_HREF: '.js-exampleHref',\n PLAY_CONTAINER: '.js-exampleContainer',\n EXAMPLE_INPUT: '.Documentation-exampleCode',\n EXAMPLE_OUTPUT: '.Documentation-exampleOutput',\n EXAMPLE_OUTPUT_CONTAINER: '.js-exampleOutputContainer',\n EXAMPLE_ERROR: '.Documentation-exampleError',\n PLAY_BUTTON: '.Documentation-examplePlayButton',\n SHARE_BUTTON: '.Documentation-exampleShareButton',\n FORMAT_BUTTON: '.Documentation-exampleFormatButton',\n RUN_BUTTON: '.Documentation-exampleRunButton',\n};\n\n/**\n * This controller enables playground examples to expand their dropdown or\n * generate shareable Go Playground URLs.\n */\nexport class PlaygroundExampleController {\n /**\n * The anchor tag used to identify the container with an example href.\n * There is only one in an example container div.\n */\n private readonly anchorEl: HTMLAnchorElement | null;\n\n /**\n * The error element\n */\n private readonly errorEl: Element | null;\n\n /**\n * Buttons that redirect to an example's playground, this element\n * only exists in executable examples.\n */\n private readonly playButtonEl: Element | null;\n private readonly shareButtonEl: Element | null;\n\n /**\n * Button that formats the code in an example's playground.\n */\n private readonly formatButtonEl: Element | null;\n\n /**\n * Button that runs the code in an example's playground, this element\n * only exists in executable examples.\n */\n private readonly runButtonEl: Element | null;\n\n /**\n * The executable code of an example.\n */\n private readonly inputEl: HTMLTextAreaElement | null;\n\n /**\n * The output of the given example code. This only exists if the\n * author of the package provides an output for this example.\n */\n private readonly outputEl: Element | null;\n\n /**\n * The container for the output.\n */\n private readonly outputContainerEl: HTMLElement | null;\n\n /**\n * @param exampleEl The div that contains playground content for the given example.\n */\n constructor(private readonly exampleEl: HTMLDetailsElement) {\n this.exampleEl = exampleEl;\n this.anchorEl = exampleEl.querySelector('a');\n this.errorEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_ERROR);\n this.playButtonEl = exampleEl.querySelector(PlayExampleClassName.PLAY_BUTTON);\n this.shareButtonEl = exampleEl.querySelector(PlayExampleClassName.SHARE_BUTTON);\n this.formatButtonEl = exampleEl.querySelector(PlayExampleClassName.FORMAT_BUTTON);\n this.runButtonEl = exampleEl.querySelector(PlayExampleClassName.RUN_BUTTON);\n this.inputEl = this.makeTextArea(exampleEl.querySelector(PlayExampleClassName.EXAMPLE_INPUT));\n this.outputEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT);\n this.outputContainerEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT_CONTAINER);\n\n // This is legacy listener to be replaced the listener for shareButtonEl.\n this.playButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.shareButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.formatButtonEl?.addEventListener('click', () => this.handleFormatButtonClick());\n this.runButtonEl?.addEventListener('click', () => this.handleRunButtonClick());\n\n if (!this.inputEl) return;\n\n this.resize();\n this.inputEl.addEventListener('keyup', () => this.resize());\n this.inputEl.addEventListener('keydown', e => this.onKeydown(e));\n }\n\n /**\n * Replace the pre element with a textarea. The examples are initially rendered\n * as pre elements so they're fully visible when JS is disabled.\n */\n makeTextArea(el: Element | null): HTMLTextAreaElement {\n const t = document.createElement('textarea');\n t.classList.add('Documentation-exampleCode', 'code');\n t.spellcheck = false;\n t.value = el?.textContent ?? '';\n el?.parentElement?.replaceChild(t, el);\n return t;\n }\n\n /**\n * Retrieve the hash value of the anchor element.\n */\n getAnchorHash(): string | undefined {\n return this.anchorEl?.hash;\n }\n\n /**\n * Expands the current playground example.\n */\n expand(): void {\n this.exampleEl.open = true;\n }\n\n /**\n * Resizes the input element to accommodate the amount of text present.\n */\n private resize(): void {\n if (this.inputEl?.value) {\n const numLineBreaks = (this.inputEl.value.match(/\\n/g) || []).length;\n // min-height + lines x line-height + padding + border\n this.inputEl.style.height = `${(20 + numLineBreaks * 20 + 12 + 2) / 16}rem`;\n }\n }\n\n /**\n * Handler to override keyboard behavior in the playground's\n * textarea element.\n *\n * Tab key inserts tabs into the example playground instead of\n * switching to the next interactive element.\n * @param e input element keyboard event.\n */\n private onKeydown(e: KeyboardEvent) {\n if (e.key === 'Tab') {\n document.execCommand('insertText', false, '\\t');\n e.preventDefault();\n }\n }\n\n /**\n * Changes the text of the example's input box.\n */\n private setInputText(output: string) {\n if (this.inputEl) {\n this.inputEl.value = output;\n }\n }\n\n /**\n * Changes the text of the example's output box.\n */\n private setOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent = output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n /**\n * Appends to the text of the example's output box.\n */\n private appendToOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent += output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n private setOutputHTML(output: string) {\n if (this.outputEl) {\n this.outputEl.innerHTML = output;\n }\n }\n\n /**\n * Sets the error message text and overwrites\n * output box to indicate a failed response.\n */\n private setErrorText(err: string) {\n if (this.errorEl) {\n this.errorEl.textContent = err;\n }\n this.setOutputText('An error has occurred\u2026');\n }\n\n private getCodeWithModFile(): string {\n let codeWithModFile = this.inputEl?.value ?? '';\n const moduleVars = document.querySelector('.js-playgroundVars')?.dataset ?? {};\n if (moduleVars.modulepath !== 'std') {\n codeWithModFile = codeWithModFile.concat(`\n-- go.mod --\nmodule play.ground\n\nrequire ${moduleVars.modulepath} ${moduleVars.version}\n`);\n }\n\n return codeWithModFile;\n }\n\n /**\n * Opens a new window to play.golang.org using the\n * example snippet's code in the playground.\n */\n private handleShareButtonClick() {\n const PLAYGROUND_BASE_URL = 'https://play.golang.org/p/';\n\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/share'), {\n method: 'POST',\n body: this.getCodeWithModFile(),\n })\n .then(res => res.text())\n .then(shareId => {\n const href = PLAYGROUND_BASE_URL + shareId;\n this.setOutputHTML(`${href} `);\n window.open(href);\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs gofmt on the example snippet in the playground.\n */\n private handleFormatButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n const body = new FormData();\n body.append('body', this.inputEl?.value ?? '');\n\n fetch(abs('/play/fmt'), {\n method: 'POST',\n body: body,\n })\n .then(res => res.json())\n .then(({ Body, Error }) => {\n this.setOutputText(Error || 'Done.');\n if (Body) {\n this.setInputText(Body);\n this.resize();\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs the code snippet in the example playground.\n */\n private handleRunButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/compile'), {\n method: 'POST',\n body: JSON.stringify({ body: this.getCodeWithModFile(), version: 2 }),\n })\n .then(res => res.json())\n .then(async ({ Events, Errors }) => {\n this.setOutputText(Errors || '');\n for (const e of Events || []) {\n this.appendToOutputText(e.Message);\n await new Promise(resolve => setTimeout(resolve, e.Delay / 1000000));\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n}\n\nexport function initPlaygrounds(): void {\n const exampleHashRegex = location.hash.match(/^#(example-.*)$/);\n if (exampleHashRegex) {\n const exampleHashEl = document.getElementById(exampleHashRegex[1]) as HTMLDetailsElement;\n if (exampleHashEl) {\n exampleHashEl.open = true;\n }\n }\n\n // We use a spread operator to convert a nodelist into an array of elements.\n const exampleHrefs = [\n ...document.querySelectorAll(PlayExampleClassName.PLAY_HREF),\n ];\n\n /**\n * Sometimes exampleHrefs and playContainers are in different order, so we\n * find an exampleHref from a common hash.\n * @param playContainer - playground container\n */\n const findExampleHash = (playContainer: PlaygroundExampleController) =>\n exampleHrefs.find(ex => {\n return ex.hash === playContainer.getAnchorHash();\n });\n\n for (const el of document.querySelectorAll(PlayExampleClassName.PLAY_CONTAINER)) {\n // There should be the same amount of hrefs referencing examples as example containers.\n const playContainer = new PlaygroundExampleController(el as HTMLDetailsElement);\n const exampleHref = findExampleHash(playContainer);\n if (exampleHref) {\n exampleHref.addEventListener('click', () => {\n playContainer.expand();\n });\n } else {\n console.warn('example href not found');\n }\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { TreeNavController } from './tree.js';\n\nexport class SelectNavController {\n constructor(private el: Element) {\n this.el.addEventListener('change', e => {\n const target = e.target as HTMLSelectElement;\n let href = target.value;\n if (!target.value.startsWith('/')) {\n href = '/' + href;\n }\n window.location.href = href;\n });\n }\n}\n\nexport function makeSelectNav(tree: TreeNavController): HTMLLabelElement {\n const label = document.createElement('label');\n label.classList.add('go-Label');\n label.setAttribute('aria-label', 'Menu');\n const select = document.createElement('select');\n select.classList.add('go-Select', 'js-selectNav');\n label.appendChild(select);\n const outline = document.createElement('optgroup');\n outline.label = 'Outline';\n select.appendChild(outline);\n const groupMap: Record = {};\n let group: HTMLOptGroupElement;\n for (const t of tree.treeitems) {\n if (Number(t.depth) > 4) continue;\n if (t.groupTreeitem) {\n group = groupMap[t.groupTreeitem.label];\n if (!group) {\n group = groupMap[t.groupTreeitem.label] = document.createElement('optgroup');\n group.label = t.groupTreeitem.label;\n select.appendChild(group);\n }\n } else {\n group = outline;\n }\n const o = document.createElement('option');\n o.label = t.label;\n o.textContent = t.label;\n o.value = (t.el as HTMLAnchorElement).href.replace(window.location.origin, '').replace('/', '');\n group.appendChild(o);\n }\n tree.addObserver(t => {\n const hash = (t.el as HTMLAnchorElement).hash;\n const value = select.querySelector(`[value$=\"${hash}\"]`)?.value;\n if (value) {\n select.value = value;\n }\n }, 50);\n return label;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * TreeNavController is the navigation tree component of the documentation page.\n * It adds accessiblity attributes to a tree, observes the heading elements\n * focus the topmost link for headings visible on the page, and implements the\n * WAI-ARIA Treeview Design Pattern with full\n * [keyboard support](https://www.w3.org/TR/wai-aria-practices/examples/treeview/treeview-2/treeview-2a.html#kbd_label).\n */\nexport class TreeNavController {\n treeitems: TreeItem[];\n\n /**\n * firstChars is the first character of each treeitem in the same order\n * as this.treeitems. We use this array to set focus by character when\n * navigating the tree with a keyboard.\n */\n private firstChars: string[];\n private firstTreeitem: TreeItem | null;\n private lastTreeitem: TreeItem | null;\n private observerCallbacks: ((t: TreeItem) => void)[];\n\n constructor(private el: HTMLElement) {\n this.treeitems = [];\n this.firstChars = [];\n this.firstTreeitem = null;\n this.lastTreeitem = null;\n this.observerCallbacks = [];\n this.init();\n }\n\n private init(): void {\n this.handleResize();\n window.addEventListener('resize', this.handleResize);\n this.findTreeItems();\n this.updateVisibleTreeitems();\n this.observeTargets();\n if (this.firstTreeitem) {\n this.firstTreeitem.el.tabIndex = 0;\n }\n }\n\n private handleResize = (): void => {\n this.el.style.setProperty('--js-tree-height', '100vh');\n this.el.style.setProperty('--js-tree-height', this.el.clientHeight + 'px');\n };\n\n private observeTargets() {\n this.addObserver(treeitem => {\n this.expandTreeitem(treeitem);\n this.setSelected(treeitem);\n // TODO: Fix scroll issue in https://golang.org/issue/47450.\n // treeitem.el.scrollIntoView({ block: 'nearest' });\n });\n\n const targets = new Map();\n const observer = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n targets.set(entry.target.id, entry.isIntersecting || entry.intersectionRatio === 1);\n }\n for (const [id, isIntersecting] of targets) {\n if (isIntersecting) {\n const active = this.treeitems.find(t =>\n (t.el as HTMLAnchorElement)?.href.endsWith(`#${id}`)\n );\n if (active) {\n for (const fn of this.observerCallbacks) {\n fn(active);\n }\n }\n break;\n }\n }\n },\n {\n threshold: 1.0,\n rootMargin: '-60px 0px 0px 0px',\n }\n );\n\n for (const href of this.treeitems.map(t => t.el.getAttribute('href'))) {\n if (href) {\n const id = href.replace(window.location.origin, '').replace('/', '').replace('#', '');\n const target = document.getElementById(id);\n if (target && !id.startsWith('example-')) {\n observer.observe(target);\n }\n }\n }\n }\n\n addObserver(fn: (t: TreeItem) => void, delay = 200): void {\n this.observerCallbacks.push(debounce(fn, delay));\n }\n\n setFocusToNextItem(currentItem: TreeItem): void {\n let nextItem = null;\n for (let i = currentItem.index + 1; i < this.treeitems.length; i++) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n nextItem = ti;\n break;\n }\n }\n if (nextItem) {\n this.setFocusToItem(nextItem);\n }\n }\n\n setFocusToPreviousItem(currentItem: TreeItem): void {\n let prevItem = null;\n for (let i = currentItem.index - 1; i > -1; i--) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n prevItem = ti;\n break;\n }\n }\n if (prevItem) {\n this.setFocusToItem(prevItem);\n }\n }\n\n setFocusToParentItem(currentItem: TreeItem): void {\n if (currentItem.groupTreeitem) {\n this.setFocusToItem(currentItem.groupTreeitem);\n }\n }\n\n setFocusToFirstItem(): void {\n this.firstTreeitem && this.setFocusToItem(this.firstTreeitem);\n }\n\n setFocusToLastItem(): void {\n this.lastTreeitem && this.setFocusToItem(this.lastTreeitem);\n }\n\n setSelected(currentItem: TreeItem): void {\n for (const l1 of this.el.querySelectorAll('[aria-expanded=\"true\"]')) {\n if (l1 === currentItem.el) continue;\n if (!l1.nextElementSibling?.contains(currentItem.el)) {\n l1.setAttribute('aria-expanded', 'false');\n }\n }\n for (const l1 of this.el.querySelectorAll('[aria-selected]')) {\n if (l1 !== currentItem.el) {\n l1.setAttribute('aria-selected', 'false');\n }\n }\n currentItem.el.setAttribute('aria-selected', 'true');\n this.updateVisibleTreeitems();\n this.setFocusToItem(currentItem, false);\n }\n\n expandTreeitem(treeitem: TreeItem): void {\n let currentItem: TreeItem | null = treeitem;\n while (currentItem) {\n if (currentItem.isExpandable) {\n currentItem.el.setAttribute('aria-expanded', 'true');\n }\n currentItem = currentItem.groupTreeitem;\n }\n this.updateVisibleTreeitems();\n }\n\n expandAllSiblingItems(currentItem: TreeItem): void {\n for (const ti of this.treeitems) {\n if (ti.groupTreeitem === currentItem.groupTreeitem && ti.isExpandable) {\n this.expandTreeitem(ti);\n }\n }\n }\n\n collapseTreeitem(currentItem: TreeItem): void {\n let groupTreeitem = null;\n\n if (currentItem.isExpanded()) {\n groupTreeitem = currentItem;\n } else {\n groupTreeitem = currentItem.groupTreeitem;\n }\n\n if (groupTreeitem) {\n groupTreeitem.el.setAttribute('aria-expanded', 'false');\n this.updateVisibleTreeitems();\n this.setFocusToItem(groupTreeitem);\n }\n }\n\n setFocusByFirstCharacter(currentItem: TreeItem, char: string): void {\n let start: number, index: number;\n char = char.toLowerCase();\n\n // Get start index for search based on position of currentItem\n start = currentItem.index + 1;\n if (start === this.treeitems.length) {\n start = 0;\n }\n\n // Check remaining slots in the menu\n index = this.getIndexFirstChars(start, char);\n\n // If not found in remaining slots, check from beginning\n if (index === -1) {\n index = this.getIndexFirstChars(0, char);\n }\n\n // If match was found...\n if (index > -1) {\n this.setFocusToItem(this.treeitems[index]);\n }\n }\n\n private findTreeItems() {\n const findItems = (el: HTMLElement, group: TreeItem | null) => {\n let ti = group;\n let curr = el.firstElementChild as HTMLElement;\n while (curr) {\n if (curr.tagName === 'A' || curr.tagName === 'SPAN') {\n ti = new TreeItem(curr, this, group);\n this.treeitems.push(ti);\n this.firstChars.push(ti.label.substring(0, 1).toLowerCase());\n }\n if (curr.firstElementChild) {\n findItems(curr, ti);\n }\n curr = curr.nextElementSibling as HTMLElement;\n }\n };\n findItems(this.el as HTMLElement, null);\n this.treeitems.map((ti, idx) => (ti.index = idx));\n }\n\n private updateVisibleTreeitems(): void {\n this.firstTreeitem = this.treeitems[0];\n\n for (const ti of this.treeitems) {\n let parent = ti.groupTreeitem;\n ti.isVisible = true;\n while (parent && parent.el !== this.el) {\n if (!parent.isExpanded()) {\n ti.isVisible = false;\n }\n parent = parent.groupTreeitem;\n }\n if (ti.isVisible) {\n this.lastTreeitem = ti;\n }\n }\n }\n\n private setFocusToItem(treeitem: TreeItem, focusEl = true) {\n treeitem.el.tabIndex = 0;\n if (focusEl) {\n treeitem.el.focus();\n }\n for (const ti of this.treeitems) {\n if (ti !== treeitem) {\n ti.el.tabIndex = -1;\n }\n }\n }\n\n private getIndexFirstChars(startIndex: number, char: string): number {\n for (let i = startIndex; i < this.firstChars.length; i++) {\n if (this.treeitems[i].isVisible && char === this.firstChars[i]) {\n return i;\n }\n }\n return -1;\n }\n}\n\nclass TreeItem {\n el: HTMLElement;\n groupTreeitem: TreeItem | null;\n label: string;\n isExpandable: boolean;\n isVisible: boolean;\n depth: number;\n index: number;\n\n private tree: TreeNavController;\n private isInGroup: boolean;\n\n constructor(el: HTMLElement, treeObj: TreeNavController, group: TreeItem | null) {\n el.tabIndex = -1;\n this.el = el;\n this.groupTreeitem = group;\n this.label = el.textContent?.trim() ?? '';\n this.tree = treeObj;\n this.depth = (group?.depth || 0) + 1;\n this.index = 0;\n\n const parent = el.parentElement;\n if (parent?.tagName.toLowerCase() === 'li') {\n parent?.setAttribute('role', 'none');\n }\n el.setAttribute('aria-level', this.depth + '');\n if (el.getAttribute('aria-label')) {\n this.label = el?.getAttribute('aria-label')?.trim() ?? '';\n }\n\n this.isExpandable = false;\n this.isVisible = false;\n this.isInGroup = !!group;\n\n let curr = el.nextElementSibling;\n while (curr) {\n if (curr.tagName.toLowerCase() == 'ul') {\n const groupId = `${group?.label ?? ''} nav group ${this.label}`.replace(/[\\W_]+/g, '_');\n el.setAttribute('aria-owns', groupId);\n el.setAttribute('aria-expanded', 'false');\n curr.setAttribute('role', 'group');\n curr.setAttribute('id', groupId);\n this.isExpandable = true;\n break;\n }\n\n curr = curr.nextElementSibling;\n }\n this.init();\n }\n\n private init() {\n this.el.tabIndex = -1;\n if (!this.el.getAttribute('role')) {\n this.el.setAttribute('role', 'treeitem');\n }\n this.el.addEventListener('keydown', this.handleKeydown.bind(this));\n this.el.addEventListener('click', this.handleClick.bind(this));\n this.el.addEventListener('focus', this.handleFocus.bind(this));\n this.el.addEventListener('blur', this.handleBlur.bind(this));\n }\n\n isExpanded() {\n if (this.isExpandable) {\n return this.el.getAttribute('aria-expanded') === 'true';\n }\n\n return false;\n }\n\n isSelected() {\n return this.el.getAttribute('aria-selected') === 'true';\n }\n\n private handleClick(event: MouseEvent) {\n // only process click events that directly happened on this treeitem\n if (event.target !== this.el && event.target !== this.el.firstElementChild) {\n return;\n }\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n }\n\n private handleFocus() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.add('focus');\n }\n\n private handleBlur() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.remove('focus');\n }\n\n private handleKeydown(event: KeyboardEvent) {\n if (event.altKey || event.ctrlKey || event.metaKey) {\n return;\n }\n\n let captured = false;\n switch (event.key) {\n case ' ':\n case 'Enter':\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n captured = true;\n } else {\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n break;\n\n case 'ArrowUp':\n this.tree.setFocusToPreviousItem(this);\n captured = true;\n break;\n\n case 'ArrowDown':\n this.tree.setFocusToNextItem(this);\n captured = true;\n break;\n\n case 'ArrowRight':\n if (this.isExpandable) {\n if (this.isExpanded()) {\n this.tree.setFocusToNextItem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n }\n captured = true;\n break;\n\n case 'ArrowLeft':\n if (this.isExpandable && this.isExpanded()) {\n this.tree.collapseTreeitem(this);\n captured = true;\n } else {\n if (this.isInGroup) {\n this.tree.setFocusToParentItem(this);\n captured = true;\n }\n }\n break;\n\n case 'Home':\n this.tree.setFocusToFirstItem();\n captured = true;\n break;\n\n case 'End':\n this.tree.setFocusToLastItem();\n captured = true;\n break;\n\n default:\n if (event.key.length === 1 && event.key.match(/\\S/)) {\n if (event.key == '*') {\n this.tree.expandAllSiblingItems(this);\n } else {\n this.tree.setFocusByFirstCharacter(this, event.key);\n }\n captured = true;\n }\n break;\n }\n\n if (captured) {\n event.stopPropagation();\n event.preventDefault();\n }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction debounce any>(func: T, wait: number) {\n let timeout: ReturnType | null;\n return (...args: Parameters) => {\n const later = () => {\n timeout = null;\n func(...args);\n };\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(later, wait);\n };\n}\n", "/*!\n * @license\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * Controller for a table element with expandable rows. Adds event listeners to\n * a toggle within a table row that controls visiblity of additional related\n * rows in the table.\n *\n * @example\n * ```typescript\n * import {ExpandableRowsTableController} from '/static/js/table';\n *\n * const el = document .querySelector('.js-myTableElement')\n * new ExpandableRowsTableController(el));\n * ```\n */\nexport class ExpandableRowsTableController {\n private rows: HTMLTableRowElement[];\n private toggles: HTMLButtonElement[];\n\n /**\n * Create a table controller.\n * @param table - The table element to which the controller binds.\n */\n constructor(private table: HTMLTableElement, private toggleAll?: HTMLButtonElement | null) {\n this.rows = Array.from(table.querySelectorAll('[data-aria-controls]'));\n this.toggles = Array.from(this.table.querySelectorAll('[aria-expanded]'));\n this.setAttributes();\n this.attachEventListeners();\n this.update();\n }\n\n /**\n * setAttributes sets data-aria-* and data-id attributes to regular\n * html attributes as a workaround for limitations from safehtml.\n */\n private setAttributes() {\n for (const a of ['data-aria-controls', 'data-aria-labelledby', 'data-id']) {\n this.table.querySelectorAll(`[${a}]`).forEach(t => {\n t.setAttribute(a.replace('data-', ''), t.getAttribute(a) ?? '');\n t.removeAttribute(a);\n });\n }\n }\n\n private attachEventListeners() {\n this.rows.forEach(t => {\n t.addEventListener('click', e => {\n this.handleToggleClick(e);\n });\n });\n this.toggleAll?.addEventListener('click', () => {\n this.expandAllItems();\n });\n\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n this.expandAllItems();\n }\n });\n }\n\n private handleToggleClick(e: MouseEvent) {\n let target = e.currentTarget as HTMLTableRowElement | null;\n if (!target?.hasAttribute('aria-expanded')) {\n target = this.table.querySelector(\n `button[aria-controls=\"${target?.getAttribute('aria-controls')}\"]`\n );\n }\n const isExpanded = target?.getAttribute('aria-expanded') === 'true';\n target?.setAttribute('aria-expanded', isExpanded ? 'false' : 'true');\n e.stopPropagation();\n this.update();\n }\n\n expandAllItems = (): void => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'true'));\n this.update();\n };\n\n private collapseAllItems = () => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'false'));\n this.update();\n };\n\n private update = () => {\n this.updateVisibleItems();\n setTimeout(() => this.updateGlobalToggle());\n };\n\n private updateVisibleItems() {\n this.rows.map(t => {\n const isExpanded = t?.getAttribute('aria-expanded') === 'true';\n const rowIds = t?.getAttribute('aria-controls')?.trimEnd().split(' ');\n rowIds?.map(id => {\n const target = document.getElementById(`${id}`);\n if (isExpanded) {\n target?.classList.add('visible');\n target?.classList.remove('hidden');\n } else {\n target?.classList.add('hidden');\n target?.classList.remove('visible');\n }\n });\n });\n }\n\n private updateGlobalToggle() {\n if (!this.toggleAll) return;\n if (this.rows.some(t => t.hasAttribute('aria-expanded'))) {\n this.toggleAll.style.display = 'block';\n }\n const someCollapsed = this.toggles.some(el => el.getAttribute('aria-expanded') === 'false');\n if (someCollapsed) {\n this.toggleAll.innerText = 'Expand all';\n this.toggleAll.onclick = this.expandAllItems;\n this.toggleAll.setAttribute('aria-label', 'Expand all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n } else {\n this.toggleAll.innerText = 'Collapse all';\n this.toggleAll.onclick = this.collapseAllItems;\n this.toggleAll.setAttribute('aria-label', 'Collapse all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n }\n }\n}\n", "import { initPlaygrounds } from 'static/shared/playground/playground';\nimport { SelectNavController, makeSelectNav } from 'static/shared/outline/select';\nimport { TreeNavController } from 'static/shared/outline/tree';\nimport { ExpandableRowsTableController } from 'static/shared/table/table';\n\ninitPlaygrounds();\n\nconst directories = document.querySelector('.js-expandableTable');\nif (directories) {\n const table = new ExpandableRowsTableController(\n directories,\n document.querySelector('.js-expandAllDirectories')\n );\n // Expand directories on page load with expand-directories query param.\n if (window.location.search.includes('expand-directories')) {\n table.expandAllItems();\n }\n\n const internalToggle = document.querySelector('.js-showInternalDirectories');\n if (internalToggle) {\n if (document.querySelector('.UnitDirectories-internal')) {\n internalToggle.style.display = 'block';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n }\n internalToggle.addEventListener('click', () => {\n if (directories.classList.contains('UnitDirectories-showInternal')) {\n directories.classList.remove('UnitDirectories-showInternal');\n internalToggle.innerText = 'Show internal';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n } else {\n directories.classList.add('UnitDirectories-showInternal');\n internalToggle.innerText = 'Hide internal';\n internalToggle.setAttribute('aria-label', 'Hide Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'hideInternal-description');\n }\n });\n }\n if (document.querySelector('html[data-local=\"true\"]')) {\n internalToggle?.click();\n }\n}\n\nconst treeEl = document.querySelector('.js-tree');\nif (treeEl) {\n const treeCtrl = new TreeNavController(treeEl);\n const select = makeSelectNav(treeCtrl);\n const mobileNav = document.querySelector('.js-mainNavMobile');\n if (mobileNav && mobileNav.firstElementChild) {\n mobileNav?.replaceChild(select, mobileNav.firstElementChild);\n }\n if (select.firstElementChild) {\n new SelectNavController(select.firstElementChild);\n }\n}\n\n/**\n * Event handlers for expanding and collapsing the readme section.\n */\nconst readme = document.querySelector('.js-readme');\nconst readmeContent = document.querySelector('.js-readmeContent');\nconst readmeOutline = document.querySelector('.js-readmeOutline');\nconst readmeExpand = document.querySelectorAll('.js-readmeExpand');\nconst readmeCollapse = document.querySelector('.js-readmeCollapse');\nconst mobileNavSelect = document.querySelector('.DocNavMobile-select');\nif (readme && readmeContent && readmeOutline && readmeExpand.length && readmeCollapse) {\n if (readme.clientHeight > 320) {\n readme?.classList.remove('UnitReadme--expanded');\n readme?.classList.add('UnitReadme--toggle');\n }\n if (window.location.hash.includes('readme')) {\n expandReadme();\n }\n mobileNavSelect?.addEventListener('change', e => {\n if ((e.target as HTMLSelectElement).value.startsWith('readme-')) {\n expandReadme();\n }\n });\n readmeExpand.forEach(el =>\n el.addEventListener('click', e => {\n e.preventDefault();\n expandReadme();\n readme.scrollIntoView();\n })\n );\n readmeCollapse.addEventListener('click', e => {\n e.preventDefault();\n readme.classList.remove('UnitReadme--expanded');\n if (readmeExpand[1]) {\n readmeExpand[1].scrollIntoView({ block: 'center' });\n }\n });\n readmeContent.addEventListener('keyup', () => {\n expandReadme();\n });\n readmeContent.addEventListener('click', () => {\n expandReadme();\n });\n readmeOutline.addEventListener('click', () => {\n expandReadme();\n });\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n expandReadme();\n }\n });\n}\n\n/**\n * expandReadme expands the readme and adds the section-readme hash to the\n * URL so it stays expanded when navigating back from an external link.\n */\nfunction expandReadme() {\n history.replaceState(null, '', `${location.pathname}${location.search}#section-readme`);\n readme?.classList.add('UnitReadme--expanded');\n}\n\n/**\n * Expand details items that are focused. This will expand\n * deprecated symbols when they are navigated to from the index\n * or a direct link.\n */\nfunction openDeprecatedSymbol() {\n if (!location.hash) return;\n const heading = document.getElementById(location.hash.slice(1));\n const grandParent = heading?.parentElement?.parentElement as HTMLDetailsElement | null;\n if (grandParent?.nodeName === 'DETAILS') {\n grandParent.open = true;\n }\n}\nopenDeprecatedSymbol();\nwindow.addEventListener('hashchange', () => openDeprecatedSymbol());\n\n/**\n * Listen for changes in the build context dropdown.\n */\ndocument.querySelectorAll('.js-buildContextSelect').forEach(el => {\n el.addEventListener('change', e => {\n window.location.search = `?GOOS=${(e.target as HTMLSelectElement).value}`;\n });\n});\n"],
- "mappings": "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",
- "names": ["getBasePath", "_a", "abs", "p", "PlayExampleClassName", "PlaygroundExampleController", "exampleEl", "_a", "_b", "_c", "_d", "e", "el", "numLineBreaks", "output", "err", "codeWithModFile", "moduleVars", "PLAYGROUND_BASE_URL", "abs", "res", "shareId", "href", "body", "Body", "Error", "Events", "Errors", "resolve", "initPlaygrounds", "exampleHashRegex", "exampleHashEl", "exampleHrefs", "findExampleHash", "playContainer", "ex", "exampleHref", "SelectNavController", "el", "e", "target", "href", "makeSelectNav", "tree", "label", "select", "outline", "groupMap", "group", "t", "o", "_a", "hash", "value", "TreeNavController", "el", "treeitem", "targets", "observer", "entries", "entry", "id", "isIntersecting", "active", "t", "_a", "fn", "href", "target", "delay", "debounce", "currentItem", "nextItem", "ti", "prevItem", "l1", "groupTreeitem", "char", "start", "index", "findItems", "group", "curr", "TreeItem", "idx", "parent", "focusEl", "startIndex", "treeObj", "_b", "_c", "_d", "_e", "groupId", "event", "captured", "func", "wait", "timeout", "args", "later", "ExpandableRowsTableController", "table", "toggleAll", "t", "a", "_a", "e", "target", "isExpanded", "rowIds", "id", "el", "initPlaygrounds", "directories", "table", "ExpandableRowsTableController", "internalToggle", "treeEl", "treeCtrl", "TreeNavController", "select", "makeSelectNav", "mobileNav", "SelectNavController", "readme", "readmeContent", "readmeOutline", "readmeExpand", "readmeCollapse", "mobileNavSelect", "expandReadme", "e", "el", "openDeprecatedSymbol", "_a", "heading", "grandParent"]
+ "sourcesContent": ["/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/gogodocs \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/gogodocs\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/gogodocs/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/gogodocs/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/*!\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the playground implementation of the documentation\n// page. The playground involves a \"play\" button that allows you to open up\n// a new link to play.golang.org using the example code.\n\n// The CSS is in static/frontend/unit/main/_doc.css\n\nimport { abs } from '../base-path/base-path';\n\n/**\n * CSS classes used by PlaygroundExampleController\n */\nconst PlayExampleClassName = {\n PLAY_HREF: '.js-exampleHref',\n PLAY_CONTAINER: '.js-exampleContainer',\n EXAMPLE_INPUT: '.Documentation-exampleCode',\n EXAMPLE_OUTPUT: '.Documentation-exampleOutput',\n EXAMPLE_OUTPUT_CONTAINER: '.js-exampleOutputContainer',\n EXAMPLE_ERROR: '.Documentation-exampleError',\n PLAY_BUTTON: '.Documentation-examplePlayButton',\n SHARE_BUTTON: '.Documentation-exampleShareButton',\n FORMAT_BUTTON: '.Documentation-exampleFormatButton',\n RUN_BUTTON: '.Documentation-exampleRunButton',\n};\n\n/**\n * This controller enables playground examples to expand their dropdown or\n * generate shareable Go Playground URLs.\n */\nexport class PlaygroundExampleController {\n /**\n * The anchor tag used to identify the container with an example href.\n * There is only one in an example container div.\n */\n private readonly anchorEl: HTMLAnchorElement | null;\n\n /**\n * The error element\n */\n private readonly errorEl: Element | null;\n\n /**\n * Buttons that redirect to an example's playground, this element\n * only exists in executable examples.\n */\n private readonly playButtonEl: Element | null;\n private readonly shareButtonEl: Element | null;\n\n /**\n * Button that formats the code in an example's playground.\n */\n private readonly formatButtonEl: Element | null;\n\n /**\n * Button that runs the code in an example's playground, this element\n * only exists in executable examples.\n */\n private readonly runButtonEl: Element | null;\n\n /**\n * The executable code of an example.\n */\n private readonly inputEl: HTMLTextAreaElement | null;\n\n /**\n * The output of the given example code. This only exists if the\n * author of the package provides an output for this example.\n */\n private readonly outputEl: Element | null;\n\n /**\n * The container for the output.\n */\n private readonly outputContainerEl: HTMLElement | null;\n\n /**\n * @param exampleEl The div that contains playground content for the given example.\n */\n constructor(private readonly exampleEl: HTMLDetailsElement) {\n this.exampleEl = exampleEl;\n this.anchorEl = exampleEl.querySelector('a');\n this.errorEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_ERROR);\n this.playButtonEl = exampleEl.querySelector(PlayExampleClassName.PLAY_BUTTON);\n this.shareButtonEl = exampleEl.querySelector(PlayExampleClassName.SHARE_BUTTON);\n this.formatButtonEl = exampleEl.querySelector(PlayExampleClassName.FORMAT_BUTTON);\n this.runButtonEl = exampleEl.querySelector(PlayExampleClassName.RUN_BUTTON);\n this.inputEl = this.makeTextArea(exampleEl.querySelector(PlayExampleClassName.EXAMPLE_INPUT));\n this.outputEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT);\n this.outputContainerEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT_CONTAINER);\n\n // This is legacy listener to be replaced the listener for shareButtonEl.\n this.playButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.shareButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.formatButtonEl?.addEventListener('click', () => this.handleFormatButtonClick());\n this.runButtonEl?.addEventListener('click', () => this.handleRunButtonClick());\n\n if (!this.inputEl) return;\n\n this.resize();\n this.inputEl.addEventListener('keyup', () => this.resize());\n this.inputEl.addEventListener('keydown', e => this.onKeydown(e));\n }\n\n /**\n * Replace the pre element with a textarea. The examples are initially rendered\n * as pre elements so they're fully visible when JS is disabled.\n */\n makeTextArea(el: Element | null): HTMLTextAreaElement {\n const t = document.createElement('textarea');\n t.classList.add('Documentation-exampleCode', 'code');\n t.spellcheck = false;\n t.value = el?.textContent ?? '';\n el?.parentElement?.replaceChild(t, el);\n return t;\n }\n\n /**\n * Retrieve the hash value of the anchor element.\n */\n getAnchorHash(): string | undefined {\n return this.anchorEl?.hash;\n }\n\n /**\n * Expands the current playground example.\n */\n expand(): void {\n this.exampleEl.open = true;\n }\n\n /**\n * Resizes the input element to accommodate the amount of text present.\n */\n private resize(): void {\n if (this.inputEl?.value) {\n const numLineBreaks = (this.inputEl.value.match(/\\n/g) || []).length;\n // min-height + lines x line-height + padding + border\n this.inputEl.style.height = `${(20 + numLineBreaks * 20 + 12 + 2) / 16}rem`;\n }\n }\n\n /**\n * Handler to override keyboard behavior in the playground's\n * textarea element.\n *\n * Tab key inserts tabs into the example playground instead of\n * switching to the next interactive element.\n * @param e input element keyboard event.\n */\n private onKeydown(e: KeyboardEvent) {\n if (e.key === 'Tab') {\n document.execCommand('insertText', false, '\\t');\n e.preventDefault();\n }\n }\n\n /**\n * Changes the text of the example's input box.\n */\n private setInputText(output: string) {\n if (this.inputEl) {\n this.inputEl.value = output;\n }\n }\n\n /**\n * Changes the text of the example's output box.\n */\n private setOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent = output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n /**\n * Appends to the text of the example's output box.\n */\n private appendToOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent += output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n private setOutputHTML(output: string) {\n if (this.outputEl) {\n this.outputEl.innerHTML = output;\n }\n }\n\n /**\n * Sets the error message text and overwrites\n * output box to indicate a failed response.\n */\n private setErrorText(err: string) {\n if (this.errorEl) {\n this.errorEl.textContent = err;\n }\n this.setOutputText('An error has occurred\u2026');\n }\n\n private getCodeWithModFile(): string {\n let codeWithModFile = this.inputEl?.value ?? '';\n const moduleVars = document.querySelector('.js-playgroundVars')?.dataset ?? {};\n if (moduleVars.modulepath !== 'std') {\n codeWithModFile = codeWithModFile.concat(`\n-- go.mod --\nmodule play.ground\n\nrequire ${moduleVars.modulepath} ${moduleVars.version}\n`);\n }\n\n return codeWithModFile;\n }\n\n /**\n * Opens a new window to play.golang.org using the\n * example snippet's code in the playground.\n */\n private handleShareButtonClick() {\n const PLAYGROUND_BASE_URL = 'https://play.golang.org/p/';\n\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/share'), {\n method: 'POST',\n body: this.getCodeWithModFile(),\n })\n .then(res => res.text())\n .then(shareId => {\n const href = PLAYGROUND_BASE_URL + shareId;\n this.setOutputHTML(`${href} `);\n window.open(href);\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs gofmt on the example snippet in the playground.\n */\n private handleFormatButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n const body = new FormData();\n body.append('body', this.inputEl?.value ?? '');\n\n fetch(abs('/play/fmt'), {\n method: 'POST',\n body: body,\n })\n .then(res => res.json())\n .then(({ Body, Error }) => {\n this.setOutputText(Error || 'Done.');\n if (Body) {\n this.setInputText(Body);\n this.resize();\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs the code snippet in the example playground.\n */\n private handleRunButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/compile'), {\n method: 'POST',\n body: JSON.stringify({ body: this.getCodeWithModFile(), version: 2 }),\n })\n .then(res => res.json())\n .then(async ({ Events, Errors }) => {\n this.setOutputText(Errors || '');\n for (const e of Events || []) {\n this.appendToOutputText(e.Message);\n await new Promise(resolve => setTimeout(resolve, e.Delay / 1000000));\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n}\n\nexport function initPlaygrounds(): void {\n const exampleHashRegex = location.hash.match(/^#(example-.*)$/);\n if (exampleHashRegex) {\n const exampleHashEl = document.getElementById(exampleHashRegex[1]) as HTMLDetailsElement;\n if (exampleHashEl) {\n exampleHashEl.open = true;\n }\n }\n\n // We use a spread operator to convert a nodelist into an array of elements.\n const exampleHrefs = [\n ...document.querySelectorAll(PlayExampleClassName.PLAY_HREF),\n ];\n\n /**\n * Sometimes exampleHrefs and playContainers are in different order, so we\n * find an exampleHref from a common hash.\n * @param playContainer - playground container\n */\n const findExampleHash = (playContainer: PlaygroundExampleController) =>\n exampleHrefs.find(ex => {\n return ex.hash === playContainer.getAnchorHash();\n });\n\n for (const el of document.querySelectorAll(PlayExampleClassName.PLAY_CONTAINER)) {\n // There should be the same amount of hrefs referencing examples as example containers.\n const playContainer = new PlaygroundExampleController(el as HTMLDetailsElement);\n const exampleHref = findExampleHash(playContainer);\n if (exampleHref) {\n exampleHref.addEventListener('click', () => {\n playContainer.expand();\n });\n } else {\n console.warn('example href not found');\n }\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { TreeNavController } from './tree.js';\n\nexport class SelectNavController {\n constructor(private el: Element) {\n this.el.addEventListener('change', e => {\n const target = e.target as HTMLSelectElement;\n let href = target.value;\n if (!target.value.startsWith('/')) {\n href = '/' + href;\n }\n window.location.href = href;\n });\n }\n}\n\nexport function makeSelectNav(tree: TreeNavController): HTMLLabelElement {\n const label = document.createElement('label');\n label.classList.add('go-Label');\n label.setAttribute('aria-label', 'Menu');\n const select = document.createElement('select');\n select.classList.add('go-Select', 'js-selectNav');\n label.appendChild(select);\n const outline = document.createElement('optgroup');\n outline.label = 'Outline';\n select.appendChild(outline);\n const groupMap: Record = {};\n let group: HTMLOptGroupElement;\n for (const t of tree.treeitems) {\n if (Number(t.depth) > 4) continue;\n if (t.groupTreeitem) {\n group = groupMap[t.groupTreeitem.label];\n if (!group) {\n group = groupMap[t.groupTreeitem.label] = document.createElement('optgroup');\n group.label = t.groupTreeitem.label;\n select.appendChild(group);\n }\n } else {\n group = outline;\n }\n const o = document.createElement('option');\n o.label = t.label;\n o.textContent = t.label;\n o.value = (t.el as HTMLAnchorElement).href.replace(window.location.origin, '').replace('/', '');\n group.appendChild(o);\n }\n tree.addObserver(t => {\n const hash = (t.el as HTMLAnchorElement).hash;\n const value = select.querySelector(`[value$=\"${hash}\"]`)?.value;\n if (value) {\n select.value = value;\n }\n }, 50);\n return label;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * TreeNavController is the navigation tree component of the documentation page.\n * It adds accessiblity attributes to a tree, observes the heading elements\n * focus the topmost link for headings visible on the page, and implements the\n * WAI-ARIA Treeview Design Pattern with full\n * [keyboard support](https://www.w3.org/TR/wai-aria-practices/examples/treeview/treeview-2/treeview-2a.html#kbd_label).\n */\nexport class TreeNavController {\n treeitems: TreeItem[];\n\n /**\n * firstChars is the first character of each treeitem in the same order\n * as this.treeitems. We use this array to set focus by character when\n * navigating the tree with a keyboard.\n */\n private firstChars: string[];\n private firstTreeitem: TreeItem | null;\n private lastTreeitem: TreeItem | null;\n private observerCallbacks: ((t: TreeItem) => void)[];\n\n constructor(private el: HTMLElement) {\n this.treeitems = [];\n this.firstChars = [];\n this.firstTreeitem = null;\n this.lastTreeitem = null;\n this.observerCallbacks = [];\n this.init();\n }\n\n private init(): void {\n this.handleResize();\n window.addEventListener('resize', this.handleResize);\n this.findTreeItems();\n this.updateVisibleTreeitems();\n this.observeTargets();\n if (this.firstTreeitem) {\n this.firstTreeitem.el.tabIndex = 0;\n }\n }\n\n private handleResize = (): void => {\n this.el.style.setProperty('--js-tree-height', '100vh');\n this.el.style.setProperty('--js-tree-height', this.el.clientHeight + 'px');\n };\n\n private observeTargets() {\n this.addObserver(treeitem => {\n this.expandTreeitem(treeitem);\n this.setSelected(treeitem);\n // TODO: Fix scroll issue in https://golang.org/issue/47450.\n // treeitem.el.scrollIntoView({ block: 'nearest' });\n });\n\n const targets = new Map();\n const observer = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n targets.set(entry.target.id, entry.isIntersecting || entry.intersectionRatio === 1);\n }\n for (const [id, isIntersecting] of targets) {\n if (isIntersecting) {\n const active = this.treeitems.find(t =>\n (t.el as HTMLAnchorElement)?.href.endsWith(`#${id}`)\n );\n if (active) {\n for (const fn of this.observerCallbacks) {\n fn(active);\n }\n }\n break;\n }\n }\n },\n {\n threshold: 1.0,\n rootMargin: '-60px 0px 0px 0px',\n }\n );\n\n for (const href of this.treeitems.map(t => t.el.getAttribute('href'))) {\n if (href) {\n const id = href.replace(window.location.origin, '').replace('/', '').replace('#', '');\n const target = document.getElementById(id);\n if (target && !id.startsWith('example-')) {\n observer.observe(target);\n }\n }\n }\n }\n\n addObserver(fn: (t: TreeItem) => void, delay = 200): void {\n this.observerCallbacks.push(debounce(fn, delay));\n }\n\n setFocusToNextItem(currentItem: TreeItem): void {\n let nextItem = null;\n for (let i = currentItem.index + 1; i < this.treeitems.length; i++) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n nextItem = ti;\n break;\n }\n }\n if (nextItem) {\n this.setFocusToItem(nextItem);\n }\n }\n\n setFocusToPreviousItem(currentItem: TreeItem): void {\n let prevItem = null;\n for (let i = currentItem.index - 1; i > -1; i--) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n prevItem = ti;\n break;\n }\n }\n if (prevItem) {\n this.setFocusToItem(prevItem);\n }\n }\n\n setFocusToParentItem(currentItem: TreeItem): void {\n if (currentItem.groupTreeitem) {\n this.setFocusToItem(currentItem.groupTreeitem);\n }\n }\n\n setFocusToFirstItem(): void {\n this.firstTreeitem && this.setFocusToItem(this.firstTreeitem);\n }\n\n setFocusToLastItem(): void {\n this.lastTreeitem && this.setFocusToItem(this.lastTreeitem);\n }\n\n setSelected(currentItem: TreeItem): void {\n for (const l1 of this.el.querySelectorAll('[aria-expanded=\"true\"]')) {\n if (l1 === currentItem.el) continue;\n if (!l1.nextElementSibling?.contains(currentItem.el)) {\n l1.setAttribute('aria-expanded', 'false');\n }\n }\n for (const l1 of this.el.querySelectorAll('[aria-selected]')) {\n if (l1 !== currentItem.el) {\n l1.setAttribute('aria-selected', 'false');\n }\n }\n currentItem.el.setAttribute('aria-selected', 'true');\n this.updateVisibleTreeitems();\n this.setFocusToItem(currentItem, false);\n }\n\n expandTreeitem(treeitem: TreeItem): void {\n let currentItem: TreeItem | null = treeitem;\n while (currentItem) {\n if (currentItem.isExpandable) {\n currentItem.el.setAttribute('aria-expanded', 'true');\n }\n currentItem = currentItem.groupTreeitem;\n }\n this.updateVisibleTreeitems();\n }\n\n expandAllSiblingItems(currentItem: TreeItem): void {\n for (const ti of this.treeitems) {\n if (ti.groupTreeitem === currentItem.groupTreeitem && ti.isExpandable) {\n this.expandTreeitem(ti);\n }\n }\n }\n\n collapseTreeitem(currentItem: TreeItem): void {\n let groupTreeitem = null;\n\n if (currentItem.isExpanded()) {\n groupTreeitem = currentItem;\n } else {\n groupTreeitem = currentItem.groupTreeitem;\n }\n\n if (groupTreeitem) {\n groupTreeitem.el.setAttribute('aria-expanded', 'false');\n this.updateVisibleTreeitems();\n this.setFocusToItem(groupTreeitem);\n }\n }\n\n setFocusByFirstCharacter(currentItem: TreeItem, char: string): void {\n let start: number, index: number;\n char = char.toLowerCase();\n\n // Get start index for search based on position of currentItem\n start = currentItem.index + 1;\n if (start === this.treeitems.length) {\n start = 0;\n }\n\n // Check remaining slots in the menu\n index = this.getIndexFirstChars(start, char);\n\n // If not found in remaining slots, check from beginning\n if (index === -1) {\n index = this.getIndexFirstChars(0, char);\n }\n\n // If match was found...\n if (index > -1) {\n this.setFocusToItem(this.treeitems[index]);\n }\n }\n\n private findTreeItems() {\n const findItems = (el: HTMLElement, group: TreeItem | null) => {\n let ti = group;\n let curr = el.firstElementChild as HTMLElement;\n while (curr) {\n if (curr.tagName === 'A' || curr.tagName === 'SPAN') {\n ti = new TreeItem(curr, this, group);\n this.treeitems.push(ti);\n this.firstChars.push(ti.label.substring(0, 1).toLowerCase());\n }\n if (curr.firstElementChild) {\n findItems(curr, ti);\n }\n curr = curr.nextElementSibling as HTMLElement;\n }\n };\n findItems(this.el as HTMLElement, null);\n this.treeitems.map((ti, idx) => (ti.index = idx));\n }\n\n private updateVisibleTreeitems(): void {\n this.firstTreeitem = this.treeitems[0];\n\n for (const ti of this.treeitems) {\n let parent = ti.groupTreeitem;\n ti.isVisible = true;\n while (parent && parent.el !== this.el) {\n if (!parent.isExpanded()) {\n ti.isVisible = false;\n }\n parent = parent.groupTreeitem;\n }\n if (ti.isVisible) {\n this.lastTreeitem = ti;\n }\n }\n }\n\n private setFocusToItem(treeitem: TreeItem, focusEl = true) {\n treeitem.el.tabIndex = 0;\n if (focusEl) {\n treeitem.el.focus();\n }\n for (const ti of this.treeitems) {\n if (ti !== treeitem) {\n ti.el.tabIndex = -1;\n }\n }\n }\n\n private getIndexFirstChars(startIndex: number, char: string): number {\n for (let i = startIndex; i < this.firstChars.length; i++) {\n if (this.treeitems[i].isVisible && char === this.firstChars[i]) {\n return i;\n }\n }\n return -1;\n }\n}\n\nclass TreeItem {\n el: HTMLElement;\n groupTreeitem: TreeItem | null;\n label: string;\n isExpandable: boolean;\n isVisible: boolean;\n depth: number;\n index: number;\n\n private tree: TreeNavController;\n private isInGroup: boolean;\n\n constructor(el: HTMLElement, treeObj: TreeNavController, group: TreeItem | null) {\n el.tabIndex = -1;\n this.el = el;\n this.groupTreeitem = group;\n this.label = el.textContent?.trim() ?? '';\n this.tree = treeObj;\n this.depth = (group?.depth || 0) + 1;\n this.index = 0;\n\n const parent = el.parentElement;\n if (parent?.tagName.toLowerCase() === 'li') {\n parent?.setAttribute('role', 'none');\n }\n el.setAttribute('aria-level', this.depth + '');\n if (el.getAttribute('aria-label')) {\n this.label = el?.getAttribute('aria-label')?.trim() ?? '';\n }\n\n this.isExpandable = false;\n this.isVisible = false;\n this.isInGroup = !!group;\n\n let curr = el.nextElementSibling;\n while (curr) {\n if (curr.tagName.toLowerCase() == 'ul') {\n const groupId = `${group?.label ?? ''} nav group ${this.label}`.replace(/[\\W_]+/g, '_');\n el.setAttribute('aria-owns', groupId);\n el.setAttribute('aria-expanded', 'false');\n curr.setAttribute('role', 'group');\n curr.setAttribute('id', groupId);\n this.isExpandable = true;\n break;\n }\n\n curr = curr.nextElementSibling;\n }\n this.init();\n }\n\n private init() {\n this.el.tabIndex = -1;\n if (!this.el.getAttribute('role')) {\n this.el.setAttribute('role', 'treeitem');\n }\n this.el.addEventListener('keydown', this.handleKeydown.bind(this));\n this.el.addEventListener('click', this.handleClick.bind(this));\n this.el.addEventListener('focus', this.handleFocus.bind(this));\n this.el.addEventListener('blur', this.handleBlur.bind(this));\n }\n\n isExpanded() {\n if (this.isExpandable) {\n return this.el.getAttribute('aria-expanded') === 'true';\n }\n\n return false;\n }\n\n isSelected() {\n return this.el.getAttribute('aria-selected') === 'true';\n }\n\n private handleClick(event: MouseEvent) {\n // only process click events that directly happened on this treeitem\n if (event.target !== this.el && event.target !== this.el.firstElementChild) {\n return;\n }\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n }\n\n private handleFocus() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.add('focus');\n }\n\n private handleBlur() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.remove('focus');\n }\n\n private handleKeydown(event: KeyboardEvent) {\n if (event.altKey || event.ctrlKey || event.metaKey) {\n return;\n }\n\n let captured = false;\n switch (event.key) {\n case ' ':\n case 'Enter':\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n captured = true;\n } else {\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n break;\n\n case 'ArrowUp':\n this.tree.setFocusToPreviousItem(this);\n captured = true;\n break;\n\n case 'ArrowDown':\n this.tree.setFocusToNextItem(this);\n captured = true;\n break;\n\n case 'ArrowRight':\n if (this.isExpandable) {\n if (this.isExpanded()) {\n this.tree.setFocusToNextItem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n }\n captured = true;\n break;\n\n case 'ArrowLeft':\n if (this.isExpandable && this.isExpanded()) {\n this.tree.collapseTreeitem(this);\n captured = true;\n } else {\n if (this.isInGroup) {\n this.tree.setFocusToParentItem(this);\n captured = true;\n }\n }\n break;\n\n case 'Home':\n this.tree.setFocusToFirstItem();\n captured = true;\n break;\n\n case 'End':\n this.tree.setFocusToLastItem();\n captured = true;\n break;\n\n default:\n if (event.key.length === 1 && event.key.match(/\\S/)) {\n if (event.key == '*') {\n this.tree.expandAllSiblingItems(this);\n } else {\n this.tree.setFocusByFirstCharacter(this, event.key);\n }\n captured = true;\n }\n break;\n }\n\n if (captured) {\n event.stopPropagation();\n event.preventDefault();\n }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction debounce any>(func: T, wait: number) {\n let timeout: ReturnType | null;\n return (...args: Parameters) => {\n const later = () => {\n timeout = null;\n func(...args);\n };\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(later, wait);\n };\n}\n", "/*!\n * @license\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * Controller for a table element with expandable rows. Adds event listeners to\n * a toggle within a table row that controls visiblity of additional related\n * rows in the table.\n *\n * @example\n * ```typescript\n * import {ExpandableRowsTableController} from '/static/js/table';\n *\n * const el = document .querySelector('.js-myTableElement')\n * new ExpandableRowsTableController(el));\n * ```\n */\nexport class ExpandableRowsTableController {\n private rows: HTMLTableRowElement[];\n private toggles: HTMLButtonElement[];\n\n /**\n * Create a table controller.\n * @param table - The table element to which the controller binds.\n */\n constructor(private table: HTMLTableElement, private toggleAll?: HTMLButtonElement | null) {\n this.rows = Array.from(table.querySelectorAll('[data-aria-controls]'));\n this.toggles = Array.from(this.table.querySelectorAll('[aria-expanded]'));\n this.setAttributes();\n this.attachEventListeners();\n this.update();\n }\n\n /**\n * setAttributes sets data-aria-* and data-id attributes to regular\n * html attributes as a workaround for limitations from safehtml.\n */\n private setAttributes() {\n for (const a of ['data-aria-controls', 'data-aria-labelledby', 'data-id']) {\n this.table.querySelectorAll(`[${a}]`).forEach(t => {\n t.setAttribute(a.replace('data-', ''), t.getAttribute(a) ?? '');\n t.removeAttribute(a);\n });\n }\n }\n\n private attachEventListeners() {\n this.rows.forEach(t => {\n t.addEventListener('click', e => {\n this.handleToggleClick(e);\n });\n });\n this.toggleAll?.addEventListener('click', () => {\n this.expandAllItems();\n });\n\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n this.expandAllItems();\n }\n });\n }\n\n private handleToggleClick(e: MouseEvent) {\n let target = e.currentTarget as HTMLTableRowElement | null;\n if (!target?.hasAttribute('aria-expanded')) {\n target = this.table.querySelector(\n `button[aria-controls=\"${target?.getAttribute('aria-controls')}\"]`\n );\n }\n const isExpanded = target?.getAttribute('aria-expanded') === 'true';\n target?.setAttribute('aria-expanded', isExpanded ? 'false' : 'true');\n e.stopPropagation();\n this.update();\n }\n\n expandAllItems = (): void => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'true'));\n this.update();\n };\n\n private collapseAllItems = () => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'false'));\n this.update();\n };\n\n private update = () => {\n this.updateVisibleItems();\n setTimeout(() => this.updateGlobalToggle());\n };\n\n private updateVisibleItems() {\n this.rows.map(t => {\n const isExpanded = t?.getAttribute('aria-expanded') === 'true';\n const rowIds = t?.getAttribute('aria-controls')?.trimEnd().split(' ');\n rowIds?.map(id => {\n const target = document.getElementById(`${id}`);\n if (isExpanded) {\n target?.classList.add('visible');\n target?.classList.remove('hidden');\n } else {\n target?.classList.add('hidden');\n target?.classList.remove('visible');\n }\n });\n });\n }\n\n private updateGlobalToggle() {\n if (!this.toggleAll) return;\n if (this.rows.some(t => t.hasAttribute('aria-expanded'))) {\n this.toggleAll.style.display = 'block';\n }\n const someCollapsed = this.toggles.some(el => el.getAttribute('aria-expanded') === 'false');\n if (someCollapsed) {\n this.toggleAll.innerText = 'Expand all';\n this.toggleAll.onclick = this.expandAllItems;\n this.toggleAll.setAttribute('aria-label', 'Expand all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n } else {\n this.toggleAll.innerText = 'Collapse all';\n this.toggleAll.onclick = this.collapseAllItems;\n this.toggleAll.setAttribute('aria-label', 'Collapse all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n }\n }\n}\n", "import { initPlaygrounds } from 'static/shared/playground/playground';\nimport { SelectNavController, makeSelectNav } from 'static/shared/outline/select';\nimport { TreeNavController } from 'static/shared/outline/tree';\nimport { ExpandableRowsTableController } from 'static/shared/table/table';\n\ninitPlaygrounds();\n\nconst directories = document.querySelector('.js-expandableTable');\nif (directories) {\n const table = new ExpandableRowsTableController(\n directories,\n document.querySelector('.js-expandAllDirectories')\n );\n // Expand directories on page load with expand-directories query param.\n if (window.location.search.includes('expand-directories')) {\n table.expandAllItems();\n }\n\n const internalToggle = document.querySelector('.js-showInternalDirectories');\n if (internalToggle) {\n if (document.querySelector('.UnitDirectories-internal')) {\n internalToggle.style.display = 'block';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n }\n internalToggle.addEventListener('click', () => {\n if (directories.classList.contains('UnitDirectories-showInternal')) {\n directories.classList.remove('UnitDirectories-showInternal');\n internalToggle.innerText = 'Show internal';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n } else {\n directories.classList.add('UnitDirectories-showInternal');\n internalToggle.innerText = 'Hide internal';\n internalToggle.setAttribute('aria-label', 'Hide Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'hideInternal-description');\n }\n });\n }\n if (document.querySelector('html[data-local=\"true\"]')) {\n internalToggle?.click();\n }\n}\n\nconst treeEl = document.querySelector('.js-tree');\nif (treeEl) {\n const treeCtrl = new TreeNavController(treeEl);\n const select = makeSelectNav(treeCtrl);\n const mobileNav = document.querySelector('.js-mainNavMobile');\n if (mobileNav && mobileNav.firstElementChild) {\n mobileNav?.replaceChild(select, mobileNav.firstElementChild);\n }\n if (select.firstElementChild) {\n new SelectNavController(select.firstElementChild);\n }\n}\n\n/**\n * Event handlers for expanding and collapsing the readme section.\n */\nconst readme = document.querySelector('.js-readme');\nconst readmeContent = document.querySelector('.js-readmeContent');\nconst readmeOutline = document.querySelector('.js-readmeOutline');\nconst readmeExpand = document.querySelectorAll('.js-readmeExpand');\nconst readmeCollapse = document.querySelector('.js-readmeCollapse');\nconst mobileNavSelect = document.querySelector('.DocNavMobile-select');\nif (readme && readmeContent && readmeOutline && readmeExpand.length && readmeCollapse) {\n if (readme.clientHeight > 320) {\n readme?.classList.remove('UnitReadme--expanded');\n readme?.classList.add('UnitReadme--toggle');\n }\n if (window.location.hash.includes('readme')) {\n expandReadme();\n }\n mobileNavSelect?.addEventListener('change', e => {\n if ((e.target as HTMLSelectElement).value.startsWith('readme-')) {\n expandReadme();\n }\n });\n readmeExpand.forEach(el =>\n el.addEventListener('click', e => {\n e.preventDefault();\n expandReadme();\n readme.scrollIntoView();\n })\n );\n readmeCollapse.addEventListener('click', e => {\n e.preventDefault();\n readme.classList.remove('UnitReadme--expanded');\n if (readmeExpand[1]) {\n readmeExpand[1].scrollIntoView({ block: 'center' });\n }\n });\n readmeContent.addEventListener('keyup', () => {\n expandReadme();\n });\n readmeContent.addEventListener('click', () => {\n expandReadme();\n });\n readmeOutline.addEventListener('click', () => {\n expandReadme();\n });\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n expandReadme();\n }\n });\n}\n\n/**\n * expandReadme expands the readme and adds the section-readme hash to the\n * URL so it stays expanded when navigating back from an external link.\n */\nfunction expandReadme() {\n history.replaceState(null, '', `${location.pathname}${location.search}#section-readme`);\n readme?.classList.add('UnitReadme--expanded');\n}\n\n/**\n * Expand details items that are focused. This will expand\n * deprecated symbols when they are navigated to from the index\n * or a direct link.\n */\nfunction openDeprecatedSymbol() {\n if (!location.hash) return;\n const heading = document.getElementById(location.hash.slice(1));\n const grandParent = heading?.parentElement?.parentElement as HTMLDetailsElement | null;\n if (grandParent?.nodeName === 'DETAILS') {\n grandParent.open = true;\n }\n}\nopenDeprecatedSymbol();\nwindow.addEventListener('hashchange', () => openDeprecatedSymbol());\n\n/**\n * Listen for changes in the build context dropdown.\n */\ndocument.querySelectorAll('.js-buildContextSelect').forEach(el => {\n el.addEventListener('change', e => {\n window.location.search = `?GOOS=${(e.target as HTMLSelectElement).value}`;\n });\n});\n\n/**\n * fork\uFF1Aunexported\uFF08\u79C1\u6709\uFF09\u7B26\u53F7 toggle\u3002\n *\n * \u80CC\u666F\uFF1Apkgsite -show-unexported flag \u8BA9 godoc \u628A\u79C1\u6709 type/func/method\n * \u90FD\u6E32\u5230 page\u3002\u4F46\u8BFB\u8005\u5927\u591A\u6570\u65F6\u5019\u53EA\u5173\u5FC3 public API\uFF0C\u79C1\u6709\u7684\u592A\u591A\u53CD\u800C\u62D6\u6162\n * \u9605\u8BFB\u3002\u8FD9\u5C42\u5728 client \u7AEF\u6309 id \u9996\u5B57\u6BCD\u5927\u5C0F\u5199\u81EA\u52A8 hide \u79C1\u6709 declaration +\n * index \u94FE\u63A5\uFF0C\u518D\u6CE8\u5165\u4E00\u4E2A toggle button \u4E00\u952E\u5207\u663E\u793A\u3002\u72B6\u6001\u7528 localStorage\n * \u8BB0\u4E0B\uFF0C\u8DE8\u9875\u4FDD\u7559\u3002\n */\n(() => {\n if (!document.querySelector('h4[data-kind]')) return; // \u975E godoc \u8BE6\u60C5\u9875\n\n // method id \u5F62\u5982 \"Type.method\"\uFF0C\u53D6\u6700\u540E\u6BB5\u5224\u79C1\u6709\uFF1B\u5176\u4ED6\u76F4\u63A5\u5224 id \u672C\u8EAB\u3002\n const isUnexported = (id: string): boolean => {\n const last = id.split('.').pop() ?? id;\n return /^[a-z]/.test(last);\n };\n\n // \u6807 declaration wrapper\uFF1Afunc \u5305\u5728 .Documentation-function\uFF1Btype / method\n // \u5305\u5728 .Documentation-type / .Documentation-typeFunc / .Documentation-typeMethod\u3002\n document.querySelectorAll('h4[data-kind][id]').forEach(h => {\n if (!isUnexported(h.id)) return;\n const wrapper = h.closest(\n '.Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod'\n );\n wrapper?.classList.add('Documentation-unexported');\n });\n\n // index \u5217\u8868\u9879\u4E5F\u6309\u94FE\u63A5\u9996\u5B57\u6BCD\u5224\n document\n .querySelectorAll(\n '.Documentation-indexFunction a[href^=\"#\"], ' +\n '.Documentation-indexType a[href^=\"#\"], ' +\n '.Documentation-indexTypeFunctions a[href^=\"#\"], ' +\n '.Documentation-indexTypeMethods a[href^=\"#\"]'\n )\n .forEach(a => {\n if (isUnexported(a.getAttribute('href')!.slice(1))) {\n a.closest('li')?.classList.add('Documentation-unexported');\n }\n });\n\n // \u6CE8\u5165 CSS\uFF08\u4E0D\u52A8 main.css build pipeline\uFF0C\u907F\u514D\u589E\u91CF\u6539 esbuild \u8F93\u51FA\uFF09\n const style = document.createElement('style');\n style.textContent =\n 'body:not(.show-unexported) .Documentation-unexported{display:none}';\n document.head.appendChild(style);\n\n // \u6CE8\u5165 toggle button\u2014\u2014\u653E Index \u6807\u9898\u65C1\u8FB9\u6700\u663E\u773C\uFF0C\u8DDF \"Show internal\" \u540C\u4F4D\n const indexHeader = document.querySelector('#pkg-index');\n if (!indexHeader) return;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'go-Button go-Button--inline';\n btn.style.marginLeft = '0.75rem';\n btn.style.fontSize = '0.875rem';\n btn.style.verticalAlign = 'middle';\n\n const STORE_KEY = 'gogodocs:showUnexported';\n const apply = (show: boolean) => {\n document.body.classList.toggle('show-unexported', show);\n btn.textContent = show ? 'Hide unexported' : 'Show unexported';\n try {\n localStorage.setItem(STORE_KEY, show ? '1' : '0');\n } catch {\n /* localStorage \u4E0D\u53EF\u7528\uFF08\u9690\u79C1\u6A21\u5F0F / \u6587\u4EF6\u534F\u8BAE\uFF09\u65F6\u5FFD\u7565\uFF0C\u53EA\u4E22\u5931\u8DE8\u9875\u8BB0\u5FC6 */\n }\n };\n\n apply(localStorage.getItem(STORE_KEY) === '1');\n btn.addEventListener('click', () =>\n apply(!document.body.classList.contains('show-unexported'))\n );\n indexHeader.appendChild(btn);\n})();\n"],
+ "mappings": "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",
+ "names": ["getBasePath", "_a", "abs", "p", "PlayExampleClassName", "PlaygroundExampleController", "exampleEl", "_a", "_b", "_c", "_d", "e", "el", "numLineBreaks", "output", "err", "codeWithModFile", "moduleVars", "PLAYGROUND_BASE_URL", "abs", "res", "shareId", "href", "body", "Body", "Error", "Events", "Errors", "resolve", "initPlaygrounds", "exampleHashRegex", "exampleHashEl", "exampleHrefs", "findExampleHash", "playContainer", "ex", "exampleHref", "SelectNavController", "el", "e", "target", "href", "makeSelectNav", "tree", "label", "select", "outline", "groupMap", "group", "t", "o", "_a", "hash", "value", "TreeNavController", "el", "treeitem", "targets", "observer", "entries", "entry", "id", "isIntersecting", "active", "t", "_a", "fn", "href", "target", "delay", "debounce", "currentItem", "nextItem", "ti", "prevItem", "l1", "groupTreeitem", "char", "start", "index", "findItems", "group", "curr", "TreeItem", "idx", "parent", "focusEl", "startIndex", "treeObj", "_b", "_c", "_d", "_e", "groupId", "event", "captured", "func", "wait", "timeout", "args", "later", "ExpandableRowsTableController", "table", "toggleAll", "t", "a", "_a", "e", "target", "isExpanded", "rowIds", "id", "el", "initPlaygrounds", "directories", "table", "ExpandableRowsTableController", "internalToggle", "treeEl", "treeCtrl", "TreeNavController", "select", "makeSelectNav", "mobileNav", "SelectNavController", "readme", "readmeContent", "readmeOutline", "readmeExpand", "readmeCollapse", "mobileNavSelect", "expandReadme", "e", "el", "openDeprecatedSymbol", "_a", "heading", "grandParent", "isUnexported", "id", "last", "h", "wrapper", "a", "style", "indexHeader", "btn", "STORE_KEY", "apply", "show"]
}
diff --git a/static/frontend/unit/main/main.ts b/static/frontend/unit/main/main.ts
index 63ff89949..64ab596b3 100644
--- a/static/frontend/unit/main/main.ts
+++ b/static/frontend/unit/main/main.ts
@@ -142,3 +142,79 @@ document.querySelectorAll('.js-buildContextSelect').forEach(el => {
window.location.search = `?GOOS=${(e.target as HTMLSelectElement).value}`;
});
});
+
+/**
+ * fork:unexported(私有)符号 toggle。
+ *
+ * 背景:pkgsite -show-unexported flag 让 godoc 把私有 type/func/method
+ * 都渲到 page。但读者大多数时候只关心 public API,私有的太多反而拖慢
+ * 阅读。这层在 client 端按 id 首字母大小写自动 hide 私有 declaration +
+ * index 链接,再注入一个 toggle button 一键切显示。状态用 localStorage
+ * 记下,跨页保留。
+ */
+(() => {
+ if (!document.querySelector('h4[data-kind]')) return; // 非 godoc 详情页
+
+ // method id 形如 "Type.method",取最后段判私有;其他直接判 id 本身。
+ const isUnexported = (id: string): boolean => {
+ const last = id.split('.').pop() ?? id;
+ return /^[a-z]/.test(last);
+ };
+
+ // 标 declaration wrapper:func 包在 .Documentation-function;type / method
+ // 包在 .Documentation-type / .Documentation-typeFunc / .Documentation-typeMethod。
+ document.querySelectorAll('h4[data-kind][id]').forEach(h => {
+ if (!isUnexported(h.id)) return;
+ const wrapper = h.closest(
+ '.Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod'
+ );
+ wrapper?.classList.add('Documentation-unexported');
+ });
+
+ // index 列表项也按链接首字母判
+ document
+ .querySelectorAll(
+ '.Documentation-indexFunction a[href^="#"], ' +
+ '.Documentation-indexType a[href^="#"], ' +
+ '.Documentation-indexTypeFunctions a[href^="#"], ' +
+ '.Documentation-indexTypeMethods a[href^="#"]'
+ )
+ .forEach(a => {
+ if (isUnexported(a.getAttribute('href')!.slice(1))) {
+ a.closest('li')?.classList.add('Documentation-unexported');
+ }
+ });
+
+ // 注入 CSS(不动 main.css build pipeline,避免增量改 esbuild 输出)
+ const style = document.createElement('style');
+ style.textContent =
+ 'body:not(.show-unexported) .Documentation-unexported{display:none}';
+ document.head.appendChild(style);
+
+ // 注入 toggle button——放 Index 标题旁边最显眼,跟 "Show internal" 同位
+ const indexHeader = document.querySelector('#pkg-index');
+ if (!indexHeader) return;
+ const btn = document.createElement('button');
+ btn.type = 'button';
+ btn.className = 'go-Button go-Button--inline';
+ btn.style.marginLeft = '0.75rem';
+ btn.style.fontSize = '0.875rem';
+ btn.style.verticalAlign = 'middle';
+
+ const STORE_KEY = 'gogodocs:showUnexported';
+ const apply = (show: boolean) => {
+ document.body.classList.toggle('show-unexported', show);
+ btn.textContent = show ? 'Hide unexported' : 'Show unexported';
+ try {
+ localStorage.setItem(STORE_KEY, show ? '1' : '0');
+ } catch {
+ /* localStorage 不可用(隐私模式 / 文件协议)时忽略,只丢失跨页记忆 */
+ }
+ };
+
+ apply(localStorage.getItem(STORE_KEY) === '1');
+ btn.addEventListener('click', () =>
+ apply(!document.body.classList.contains('show-unexported'))
+ );
+ indexHeader.appendChild(btn);
+})();
From 68b3f107a29aa060a23267c4c69ec82f50c56790 Mon Sep 17 00:00:00 2001
From: Yechi Yang <95576172+NickWilde18@users.noreply.github.com>
Date: Thu, 7 May 2026 17:12:16 +0800
Subject: [PATCH 10/26] =?UTF-8?q?fix(toggle):=20unexported=20toggle=20?=
=?UTF-8?q?=E8=A6=86=E7=9B=96=E4=BE=A7=E8=BE=B9=E6=A0=8F=20+=20=E6=8E=92?=
=?UTF-8?q?=E9=99=A4=20page=20anchor=20=E8=AF=AF=E6=A0=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
之前只标 .Documentation-index* 中央列表,左侧边栏 .go-Tree outline 没
覆盖——侧边栏私有函数链接还是显示。selector 加 '.go-Tree a[href^="#"]'。
isUnexported 加头部 anchor 排除:pkg- / section- / hdr- 起头的是页面
导航锚点(pkg-overview / section-readme / hdr-... 等),全小写但不是
Go 符号,扫到会误标整段隐藏。
---
static/frontend/unit/main/main.js | 2 +-
static/frontend/unit/main/main.js.map | 4 ++--
static/frontend/unit/main/main.ts | 12 ++++++++++--
3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/static/frontend/unit/main/main.js b/static/frontend/unit/main/main.js
index 67dc3cbe3..c1a1cbba7 100644
--- a/static/frontend/unit/main/main.js
+++ b/static/frontend/unit/main/main.js
@@ -3,7 +3,7 @@ function H(){var l;return(l=document.documentElement.dataset.basePath)!=null?l:"
module play.ground
require ${t.modulepath} ${t.version}
-`)),e}handleShareButtonClick(){let e="https://play.golang.org/p/";this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/share"),{method:"POST",body:this.getCodeWithModFile()}).then(t=>t.text()).then(t=>{let i=e+t;this.setOutputHTML(`${i} `),window.open(i)}).catch(t=>{this.setErrorText(t)})}handleFormatButtonClick(){var t,i;this.setOutputText("Waiting for remote server\u2026");let e=new FormData;e.append("body",(i=(t=this.inputEl)==null?void 0:t.value)!=null?i:""),fetch(p("/play/fmt"),{method:"POST",body:e}).then(s=>s.json()).then(({Body:s,Error:n})=>{this.setOutputText(n||"Done."),s&&(this.setInputText(s),this.resize())}).catch(s=>{this.setErrorText(s)})}handleRunButtonClick(){this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/compile"),{method:"POST",body:JSON.stringify({body:this.getCodeWithModFile(),version:2})}).then(e=>e.json()).then(async({Events:e,Errors:t})=>{this.setOutputText(t||"");for(let i of e||[])this.appendToOutputText(i.Message),await new Promise(s=>setTimeout(s,i.Delay/1e6))}).catch(e=>{this.setErrorText(e)})}};function C(){let l=location.hash.match(/^#(example-.*)$/);if(l){let i=document.getElementById(l[1]);i&&(i.open=!0)}let e=[...document.querySelectorAll(u.PLAY_HREF)],t=i=>e.find(s=>s.hash===i.getAnchorHash());for(let i of document.querySelectorAll(u.PLAY_CONTAINER)){let s=new x(i),n=t(s);n?n.addEventListener("click",()=>{s.expand()}):console.warn("example href not found")}}var f=class{constructor(e){this.el=e;this.el.addEventListener("change",t=>{let i=t.target,s=i.value;i.value.startsWith("/")||(s="/"+s),window.location.href=s})}};function I(l){let e=document.createElement("label");e.classList.add("go-Label"),e.setAttribute("aria-label","Menu");let t=document.createElement("select");t.classList.add("go-Select","js-selectNav"),e.appendChild(t);let i=document.createElement("optgroup");i.label="Outline",t.appendChild(i);let s={},n;for(let r of l.treeitems){if(Number(r.depth)>4)continue;r.groupTreeitem?(n=s[r.groupTreeitem.label],n||(n=s[r.groupTreeitem.label]=document.createElement("optgroup"),n.label=r.groupTreeitem.label,t.appendChild(n))):n=i;let a=document.createElement("option");a.label=r.label,a.textContent=r.label,a.value=r.el.href.replace(window.location.origin,"").replace("/",""),n.appendChild(a)}return l.addObserver(r=>{var h;let a=r.el.hash,d=(h=t.querySelector(`[value$="${a}"]`))==null?void 0:h.value;d&&(t.value=d)},50),e}var E=class{constructor(e){this.el=e;this.handleResize=()=>{this.el.style.setProperty("--js-tree-height","100vh"),this.el.style.setProperty("--js-tree-height",this.el.clientHeight+"px")};this.treeitems=[],this.firstChars=[],this.firstTreeitem=null,this.lastTreeitem=null,this.observerCallbacks=[],this.init()}init(){this.handleResize(),window.addEventListener("resize",this.handleResize),this.findTreeItems(),this.updateVisibleTreeitems(),this.observeTargets(),this.firstTreeitem&&(this.firstTreeitem.el.tabIndex=0)}observeTargets(){this.addObserver(i=>{this.expandTreeitem(i),this.setSelected(i)});let e=new Map,t=new IntersectionObserver(i=>{for(let s of i)e.set(s.target.id,s.isIntersecting||s.intersectionRatio===1);for(let[s,n]of e)if(n){let r=this.treeitems.find(a=>{var d;return(d=a.el)==null?void 0:d.href.endsWith(`#${s}`)});if(r)for(let a of this.observerCallbacks)a(r);break}},{threshold:1,rootMargin:"-60px 0px 0px 0px"});for(let i of this.treeitems.map(s=>s.el.getAttribute("href")))if(i){let s=i.replace(window.location.origin,"").replace("/","").replace("#",""),n=document.getElementById(s);n&&!s.startsWith("example-")&&t.observe(n)}}addObserver(e,t=200){this.observerCallbacks.push(O(e,t))}setFocusToNextItem(e){let t=null;for(let i=e.index+1;i-1;i--){let s=this.treeitems[i];if(s.isVisible){t=s;break}}t&&this.setFocusToItem(t)}setFocusToParentItem(e){e.groupTreeitem&&this.setFocusToItem(e.groupTreeitem)}setFocusToFirstItem(){this.firstTreeitem&&this.setFocusToItem(this.firstTreeitem)}setFocusToLastItem(){this.lastTreeitem&&this.setFocusToItem(this.lastTreeitem)}setSelected(e){var t;for(let i of this.el.querySelectorAll('[aria-expanded="true"]'))i!==e.el&&((t=i.nextElementSibling)!=null&&t.contains(e.el)||i.setAttribute("aria-expanded","false"));for(let i of this.el.querySelectorAll("[aria-selected]"))i!==e.el&&i.setAttribute("aria-selected","false");e.el.setAttribute("aria-selected","true"),this.updateVisibleTreeitems(),this.setFocusToItem(e,!1)}expandTreeitem(e){let t=e;for(;t;)t.isExpandable&&t.el.setAttribute("aria-expanded","true"),t=t.groupTreeitem;this.updateVisibleTreeitems()}expandAllSiblingItems(e){for(let t of this.treeitems)t.groupTreeitem===e.groupTreeitem&&t.isExpandable&&this.expandTreeitem(t)}collapseTreeitem(e){let t=null;e.isExpanded()?t=e:t=e.groupTreeitem,t&&(t.el.setAttribute("aria-expanded","false"),this.updateVisibleTreeitems(),this.setFocusToItem(t))}setFocusByFirstCharacter(e,t){let i,s;t=t.toLowerCase(),i=e.index+1,i===this.treeitems.length&&(i=0),s=this.getIndexFirstChars(i,t),s===-1&&(s=this.getIndexFirstChars(0,t)),s>-1&&this.setFocusToItem(this.treeitems[s])}findTreeItems(){let e=(t,i)=>{let s=i,n=t.firstElementChild;for(;n;)(n.tagName==="A"||n.tagName==="SPAN")&&(s=new g(n,this,i),this.treeitems.push(s),this.firstChars.push(s.label.substring(0,1).toLowerCase())),n.firstElementChild&&e(n,s),n=n.nextElementSibling};e(this.el,null),this.treeitems.map((t,i)=>t.index=i)}updateVisibleTreeitems(){this.firstTreeitem=this.treeitems[0];for(let e of this.treeitems){let t=e.groupTreeitem;for(e.isVisible=!0;t&&t.el!==this.el;)t.isExpanded()||(e.isVisible=!1),t=t.groupTreeitem;e.isVisible&&(this.lastTreeitem=e)}}setFocusToItem(e,t=!0){e.el.tabIndex=0,t&&e.el.focus();for(let i of this.treeitems)i!==e&&(i.el.tabIndex=-1)}getIndexFirstChars(e,t){for(let i=e;i{let s=()=>{t=null,l(...i)};t&&clearTimeout(t),t=setTimeout(s,e)}}var T=class{constructor(e,t){this.table=e;this.toggleAll=t;this.expandAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","true")),this.update()};this.collapseAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","false")),this.update()};this.update=()=>{this.updateVisibleItems(),setTimeout(()=>this.updateGlobalToggle())};this.rows=Array.from(e.querySelectorAll("[data-aria-controls]")),this.toggles=Array.from(this.table.querySelectorAll("[aria-expanded]")),this.setAttributes(),this.attachEventListeners(),this.update()}setAttributes(){for(let e of["data-aria-controls","data-aria-labelledby","data-id"])this.table.querySelectorAll(`[${e}]`).forEach(t=>{var i;t.setAttribute(e.replace("data-",""),(i=t.getAttribute(e))!=null?i:""),t.removeAttribute(e)})}attachEventListeners(){var e;this.rows.forEach(t=>{t.addEventListener("click",i=>{this.handleToggleClick(i)})}),(e=this.toggleAll)==null||e.addEventListener("click",()=>{this.expandAllItems()}),document.addEventListener("keydown",t=>{(t.ctrlKey||t.metaKey)&&t.key==="f"&&this.expandAllItems()})}handleToggleClick(e){let t=e.currentTarget;t!=null&&t.hasAttribute("aria-expanded")||(t=this.table.querySelector(`button[aria-controls="${t==null?void 0:t.getAttribute("aria-controls")}"]`));let i=(t==null?void 0:t.getAttribute("aria-expanded"))==="true";t==null||t.setAttribute("aria-expanded",i?"false":"true"),e.stopPropagation(),this.update()}updateVisibleItems(){this.rows.map(e=>{var s;let t=(e==null?void 0:e.getAttribute("aria-expanded"))==="true",i=(s=e==null?void 0:e.getAttribute("aria-controls"))==null?void 0:s.trimEnd().split(" ");i==null||i.map(n=>{let r=document.getElementById(`${n}`);t?(r==null||r.classList.add("visible"),r==null||r.classList.remove("hidden")):(r==null||r.classList.add("hidden"),r==null||r.classList.remove("visible"))})})}updateGlobalToggle(){if(!this.toggleAll)return;this.rows.some(t=>t.hasAttribute("aria-expanded"))&&(this.toggleAll.style.display="block"),this.toggles.some(t=>t.getAttribute("aria-expanded")==="false")?(this.toggleAll.innerText="Expand all",this.toggleAll.onclick=this.expandAllItems,this.toggleAll.setAttribute("aria-label","Expand all directories"),this.toggleAll.setAttribute("aria-live","polite")):(this.toggleAll.innerText="Collapse all",this.toggleAll.onclick=this.collapseAllItems,this.toggleAll.setAttribute("aria-label","Collapse all directories"),this.toggleAll.setAttribute("aria-live","polite"))}};C();var m=document.querySelector(".js-expandableTable");if(m){let l=new T(m,document.querySelector(".js-expandAllDirectories"));window.location.search.includes("expand-directories")&&l.expandAllItems();let e=document.querySelector(".js-showInternalDirectories");e&&(document.querySelector(".UnitDirectories-internal")&&(e.style.display="block",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-describedby","showInternal-description")),e.addEventListener("click",()=>{m.classList.contains("UnitDirectories-showInternal")?(m.classList.remove("UnitDirectories-showInternal"),e.innerText="Show internal",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","showInternal-description")):(m.classList.add("UnitDirectories-showInternal"),e.innerText="Hide internal",e.setAttribute("aria-label","Hide Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","hideInternal-description"))})),document.querySelector('html[data-local="true"]')&&(e==null||e.click())}var S=document.querySelector(".js-tree");if(S){let l=new E(S),e=I(l),t=document.querySelector(".js-mainNavMobile");t&&t.firstElementChild&&(t==null||t.replaceChild(e,t.firstElementChild)),e.firstElementChild&&new f(e.firstElementChild)}var o=document.querySelector(".js-readme"),v=document.querySelector(".js-readmeContent"),w=document.querySelector(".js-readmeOutline"),b=document.querySelectorAll(".js-readmeExpand"),M=document.querySelector(".js-readmeCollapse"),y=document.querySelector(".DocNavMobile-select");o&&v&&w&&b.length&&M&&(o.clientHeight>320&&(o==null||o.classList.remove("UnitReadme--expanded"),o==null||o.classList.add("UnitReadme--toggle")),window.location.hash.includes("readme")&&c(),y==null||y.addEventListener("change",l=>{l.target.value.startsWith("readme-")&&c()}),b.forEach(l=>l.addEventListener("click",e=>{e.preventDefault(),c(),o.scrollIntoView()})),M.addEventListener("click",l=>{l.preventDefault(),o.classList.remove("UnitReadme--expanded"),b[1]&&b[1].scrollIntoView({block:"center"})}),v.addEventListener("keyup",()=>{c()}),v.addEventListener("click",()=>{c()}),w.addEventListener("click",()=>{c()}),document.addEventListener("keydown",l=>{(l.ctrlKey||l.metaKey)&&l.key==="f"&&c()}));function c(){history.replaceState(null,"",`${location.pathname}${location.search}#section-readme`),o==null||o.classList.add("UnitReadme--expanded")}function k(){var t;if(!location.hash)return;let l=document.getElementById(location.hash.slice(1)),e=(t=l==null?void 0:l.parentElement)==null?void 0:t.parentElement;(e==null?void 0:e.nodeName)==="DETAILS"&&(e.open=!0)}k();window.addEventListener("hashchange",()=>k());document.querySelectorAll(".js-buildContextSelect").forEach(l=>{l.addEventListener("change",e=>{window.location.search=`?GOOS=${e.target.value}`})});(()=>{if(!document.querySelector("h4[data-kind]"))return;let l=r=>{var d;let a=(d=r.split(".").pop())!=null?d:r;return/^[a-z]/.test(a)};document.querySelectorAll("h4[data-kind][id]").forEach(r=>{if(!l(r.id))return;let a=r.closest(".Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod");a==null||a.classList.add("Documentation-unexported")}),document.querySelectorAll('.Documentation-indexFunction a[href^="#"], .Documentation-indexType a[href^="#"], .Documentation-indexTypeFunctions a[href^="#"], .Documentation-indexTypeMethods a[href^="#"]').forEach(r=>{var a;l(r.getAttribute("href").slice(1))&&((a=r.closest("li"))==null||a.classList.add("Documentation-unexported"))});let e=document.createElement("style");e.textContent="body:not(.show-unexported) .Documentation-unexported{display:none}",document.head.appendChild(e);let t=document.querySelector("#pkg-index");if(!t)return;let i=document.createElement("button");i.type="button",i.className="go-Button go-Button--inline",i.style.marginLeft="0.75rem",i.style.fontSize="0.875rem",i.style.verticalAlign="middle";let s="gogodocs:showUnexported",n=r=>{document.body.classList.toggle("show-unexported",r),i.textContent=r?"Hide unexported":"Show unexported";try{localStorage.setItem(s,r?"1":"0")}catch{}};n(localStorage.getItem(s)==="1"),i.addEventListener("click",()=>n(!document.body.classList.contains("show-unexported"))),t.appendChild(i)})();
+`)),e}handleShareButtonClick(){let e="https://play.golang.org/p/";this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/share"),{method:"POST",body:this.getCodeWithModFile()}).then(t=>t.text()).then(t=>{let i=e+t;this.setOutputHTML(`${i} `),window.open(i)}).catch(t=>{this.setErrorText(t)})}handleFormatButtonClick(){var t,i;this.setOutputText("Waiting for remote server\u2026");let e=new FormData;e.append("body",(i=(t=this.inputEl)==null?void 0:t.value)!=null?i:""),fetch(p("/play/fmt"),{method:"POST",body:e}).then(s=>s.json()).then(({Body:s,Error:n})=>{this.setOutputText(n||"Done."),s&&(this.setInputText(s),this.resize())}).catch(s=>{this.setErrorText(s)})}handleRunButtonClick(){this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/compile"),{method:"POST",body:JSON.stringify({body:this.getCodeWithModFile(),version:2})}).then(e=>e.json()).then(async({Events:e,Errors:t})=>{this.setOutputText(t||"");for(let i of e||[])this.appendToOutputText(i.Message),await new Promise(s=>setTimeout(s,i.Delay/1e6))}).catch(e=>{this.setErrorText(e)})}};function C(){let l=location.hash.match(/^#(example-.*)$/);if(l){let i=document.getElementById(l[1]);i&&(i.open=!0)}let e=[...document.querySelectorAll(u.PLAY_HREF)],t=i=>e.find(s=>s.hash===i.getAnchorHash());for(let i of document.querySelectorAll(u.PLAY_CONTAINER)){let s=new x(i),n=t(s);n?n.addEventListener("click",()=>{s.expand()}):console.warn("example href not found")}}var f=class{constructor(e){this.el=e;this.el.addEventListener("change",t=>{let i=t.target,s=i.value;i.value.startsWith("/")||(s="/"+s),window.location.href=s})}};function I(l){let e=document.createElement("label");e.classList.add("go-Label"),e.setAttribute("aria-label","Menu");let t=document.createElement("select");t.classList.add("go-Select","js-selectNav"),e.appendChild(t);let i=document.createElement("optgroup");i.label="Outline",t.appendChild(i);let s={},n;for(let r of l.treeitems){if(Number(r.depth)>4)continue;r.groupTreeitem?(n=s[r.groupTreeitem.label],n||(n=s[r.groupTreeitem.label]=document.createElement("optgroup"),n.label=r.groupTreeitem.label,t.appendChild(n))):n=i;let a=document.createElement("option");a.label=r.label,a.textContent=r.label,a.value=r.el.href.replace(window.location.origin,"").replace("/",""),n.appendChild(a)}return l.addObserver(r=>{var h;let a=r.el.hash,d=(h=t.querySelector(`[value$="${a}"]`))==null?void 0:h.value;d&&(t.value=d)},50),e}var E=class{constructor(e){this.el=e;this.handleResize=()=>{this.el.style.setProperty("--js-tree-height","100vh"),this.el.style.setProperty("--js-tree-height",this.el.clientHeight+"px")};this.treeitems=[],this.firstChars=[],this.firstTreeitem=null,this.lastTreeitem=null,this.observerCallbacks=[],this.init()}init(){this.handleResize(),window.addEventListener("resize",this.handleResize),this.findTreeItems(),this.updateVisibleTreeitems(),this.observeTargets(),this.firstTreeitem&&(this.firstTreeitem.el.tabIndex=0)}observeTargets(){this.addObserver(i=>{this.expandTreeitem(i),this.setSelected(i)});let e=new Map,t=new IntersectionObserver(i=>{for(let s of i)e.set(s.target.id,s.isIntersecting||s.intersectionRatio===1);for(let[s,n]of e)if(n){let r=this.treeitems.find(a=>{var d;return(d=a.el)==null?void 0:d.href.endsWith(`#${s}`)});if(r)for(let a of this.observerCallbacks)a(r);break}},{threshold:1,rootMargin:"-60px 0px 0px 0px"});for(let i of this.treeitems.map(s=>s.el.getAttribute("href")))if(i){let s=i.replace(window.location.origin,"").replace("/","").replace("#",""),n=document.getElementById(s);n&&!s.startsWith("example-")&&t.observe(n)}}addObserver(e,t=200){this.observerCallbacks.push(O(e,t))}setFocusToNextItem(e){let t=null;for(let i=e.index+1;i-1;i--){let s=this.treeitems[i];if(s.isVisible){t=s;break}}t&&this.setFocusToItem(t)}setFocusToParentItem(e){e.groupTreeitem&&this.setFocusToItem(e.groupTreeitem)}setFocusToFirstItem(){this.firstTreeitem&&this.setFocusToItem(this.firstTreeitem)}setFocusToLastItem(){this.lastTreeitem&&this.setFocusToItem(this.lastTreeitem)}setSelected(e){var t;for(let i of this.el.querySelectorAll('[aria-expanded="true"]'))i!==e.el&&((t=i.nextElementSibling)!=null&&t.contains(e.el)||i.setAttribute("aria-expanded","false"));for(let i of this.el.querySelectorAll("[aria-selected]"))i!==e.el&&i.setAttribute("aria-selected","false");e.el.setAttribute("aria-selected","true"),this.updateVisibleTreeitems(),this.setFocusToItem(e,!1)}expandTreeitem(e){let t=e;for(;t;)t.isExpandable&&t.el.setAttribute("aria-expanded","true"),t=t.groupTreeitem;this.updateVisibleTreeitems()}expandAllSiblingItems(e){for(let t of this.treeitems)t.groupTreeitem===e.groupTreeitem&&t.isExpandable&&this.expandTreeitem(t)}collapseTreeitem(e){let t=null;e.isExpanded()?t=e:t=e.groupTreeitem,t&&(t.el.setAttribute("aria-expanded","false"),this.updateVisibleTreeitems(),this.setFocusToItem(t))}setFocusByFirstCharacter(e,t){let i,s;t=t.toLowerCase(),i=e.index+1,i===this.treeitems.length&&(i=0),s=this.getIndexFirstChars(i,t),s===-1&&(s=this.getIndexFirstChars(0,t)),s>-1&&this.setFocusToItem(this.treeitems[s])}findTreeItems(){let e=(t,i)=>{let s=i,n=t.firstElementChild;for(;n;)(n.tagName==="A"||n.tagName==="SPAN")&&(s=new g(n,this,i),this.treeitems.push(s),this.firstChars.push(s.label.substring(0,1).toLowerCase())),n.firstElementChild&&e(n,s),n=n.nextElementSibling};e(this.el,null),this.treeitems.map((t,i)=>t.index=i)}updateVisibleTreeitems(){this.firstTreeitem=this.treeitems[0];for(let e of this.treeitems){let t=e.groupTreeitem;for(e.isVisible=!0;t&&t.el!==this.el;)t.isExpanded()||(e.isVisible=!1),t=t.groupTreeitem;e.isVisible&&(this.lastTreeitem=e)}}setFocusToItem(e,t=!0){e.el.tabIndex=0,t&&e.el.focus();for(let i of this.treeitems)i!==e&&(i.el.tabIndex=-1)}getIndexFirstChars(e,t){for(let i=e;i{let s=()=>{t=null,l(...i)};t&&clearTimeout(t),t=setTimeout(s,e)}}var T=class{constructor(e,t){this.table=e;this.toggleAll=t;this.expandAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","true")),this.update()};this.collapseAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","false")),this.update()};this.update=()=>{this.updateVisibleItems(),setTimeout(()=>this.updateGlobalToggle())};this.rows=Array.from(e.querySelectorAll("[data-aria-controls]")),this.toggles=Array.from(this.table.querySelectorAll("[aria-expanded]")),this.setAttributes(),this.attachEventListeners(),this.update()}setAttributes(){for(let e of["data-aria-controls","data-aria-labelledby","data-id"])this.table.querySelectorAll(`[${e}]`).forEach(t=>{var i;t.setAttribute(e.replace("data-",""),(i=t.getAttribute(e))!=null?i:""),t.removeAttribute(e)})}attachEventListeners(){var e;this.rows.forEach(t=>{t.addEventListener("click",i=>{this.handleToggleClick(i)})}),(e=this.toggleAll)==null||e.addEventListener("click",()=>{this.expandAllItems()}),document.addEventListener("keydown",t=>{(t.ctrlKey||t.metaKey)&&t.key==="f"&&this.expandAllItems()})}handleToggleClick(e){let t=e.currentTarget;t!=null&&t.hasAttribute("aria-expanded")||(t=this.table.querySelector(`button[aria-controls="${t==null?void 0:t.getAttribute("aria-controls")}"]`));let i=(t==null?void 0:t.getAttribute("aria-expanded"))==="true";t==null||t.setAttribute("aria-expanded",i?"false":"true"),e.stopPropagation(),this.update()}updateVisibleItems(){this.rows.map(e=>{var s;let t=(e==null?void 0:e.getAttribute("aria-expanded"))==="true",i=(s=e==null?void 0:e.getAttribute("aria-controls"))==null?void 0:s.trimEnd().split(" ");i==null||i.map(n=>{let r=document.getElementById(`${n}`);t?(r==null||r.classList.add("visible"),r==null||r.classList.remove("hidden")):(r==null||r.classList.add("hidden"),r==null||r.classList.remove("visible"))})})}updateGlobalToggle(){if(!this.toggleAll)return;this.rows.some(t=>t.hasAttribute("aria-expanded"))&&(this.toggleAll.style.display="block"),this.toggles.some(t=>t.getAttribute("aria-expanded")==="false")?(this.toggleAll.innerText="Expand all",this.toggleAll.onclick=this.expandAllItems,this.toggleAll.setAttribute("aria-label","Expand all directories"),this.toggleAll.setAttribute("aria-live","polite")):(this.toggleAll.innerText="Collapse all",this.toggleAll.onclick=this.collapseAllItems,this.toggleAll.setAttribute("aria-label","Collapse all directories"),this.toggleAll.setAttribute("aria-live","polite"))}};C();var m=document.querySelector(".js-expandableTable");if(m){let l=new T(m,document.querySelector(".js-expandAllDirectories"));window.location.search.includes("expand-directories")&&l.expandAllItems();let e=document.querySelector(".js-showInternalDirectories");e&&(document.querySelector(".UnitDirectories-internal")&&(e.style.display="block",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-describedby","showInternal-description")),e.addEventListener("click",()=>{m.classList.contains("UnitDirectories-showInternal")?(m.classList.remove("UnitDirectories-showInternal"),e.innerText="Show internal",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","showInternal-description")):(m.classList.add("UnitDirectories-showInternal"),e.innerText="Hide internal",e.setAttribute("aria-label","Hide Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","hideInternal-description"))})),document.querySelector('html[data-local="true"]')&&(e==null||e.click())}var S=document.querySelector(".js-tree");if(S){let l=new E(S),e=I(l),t=document.querySelector(".js-mainNavMobile");t&&t.firstElementChild&&(t==null||t.replaceChild(e,t.firstElementChild)),e.firstElementChild&&new f(e.firstElementChild)}var o=document.querySelector(".js-readme"),v=document.querySelector(".js-readmeContent"),w=document.querySelector(".js-readmeOutline"),b=document.querySelectorAll(".js-readmeExpand"),k=document.querySelector(".js-readmeCollapse"),y=document.querySelector(".DocNavMobile-select");o&&v&&w&&b.length&&k&&(o.clientHeight>320&&(o==null||o.classList.remove("UnitReadme--expanded"),o==null||o.classList.add("UnitReadme--toggle")),window.location.hash.includes("readme")&&c(),y==null||y.addEventListener("change",l=>{l.target.value.startsWith("readme-")&&c()}),b.forEach(l=>l.addEventListener("click",e=>{e.preventDefault(),c(),o.scrollIntoView()})),k.addEventListener("click",l=>{l.preventDefault(),o.classList.remove("UnitReadme--expanded"),b[1]&&b[1].scrollIntoView({block:"center"})}),v.addEventListener("keyup",()=>{c()}),v.addEventListener("click",()=>{c()}),w.addEventListener("click",()=>{c()}),document.addEventListener("keydown",l=>{(l.ctrlKey||l.metaKey)&&l.key==="f"&&c()}));function c(){history.replaceState(null,"",`${location.pathname}${location.search}#section-readme`),o==null||o.classList.add("UnitReadme--expanded")}function M(){var t;if(!location.hash)return;let l=document.getElementById(location.hash.slice(1)),e=(t=l==null?void 0:l.parentElement)==null?void 0:t.parentElement;(e==null?void 0:e.nodeName)==="DETAILS"&&(e.open=!0)}M();window.addEventListener("hashchange",()=>M());document.querySelectorAll(".js-buildContextSelect").forEach(l=>{l.addEventListener("change",e=>{window.location.search=`?GOOS=${e.target.value}`})});(()=>{if(!document.querySelector("h4[data-kind]"))return;let l=r=>{var d;if(r.startsWith("pkg-")||r.startsWith("section-")||r.startsWith("hdr-"))return!1;let a=(d=r.split(".").pop())!=null?d:r;return/^[a-z]/.test(a)};document.querySelectorAll("h4[data-kind][id]").forEach(r=>{if(!l(r.id))return;let a=r.closest(".Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod");a==null||a.classList.add("Documentation-unexported")}),document.querySelectorAll('.Documentation-indexFunction a[href^="#"], .Documentation-indexType a[href^="#"], .Documentation-indexTypeFunctions a[href^="#"], .Documentation-indexTypeMethods a[href^="#"], .go-Tree a[href^="#"]').forEach(r=>{var a;l(r.getAttribute("href").slice(1))&&((a=r.closest("li"))==null||a.classList.add("Documentation-unexported"))});let e=document.createElement("style");e.textContent="body:not(.show-unexported) .Documentation-unexported{display:none}",document.head.appendChild(e);let t=document.querySelector("#pkg-index");if(!t)return;let i=document.createElement("button");i.type="button",i.className="go-Button go-Button--inline",i.style.marginLeft="0.75rem",i.style.fontSize="0.875rem",i.style.verticalAlign="middle";let s="gogodocs:showUnexported",n=r=>{document.body.classList.toggle("show-unexported",r),i.textContent=r?"Hide unexported":"Show unexported";try{localStorage.setItem(s,r?"1":"0")}catch{}};n(localStorage.getItem(s)==="1"),i.addEventListener("click",()=>n(!document.body.classList.contains("show-unexported"))),t.appendChild(i)})();
/**
* @license
* Copyright 2024 The Go Authors. All rights reserved.
diff --git a/static/frontend/unit/main/main.js.map b/static/frontend/unit/main/main.js.map
index 154bedf34..fbe0b88dd 100644
--- a/static/frontend/unit/main/main.js.map
+++ b/static/frontend/unit/main/main.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../../shared/base-path/base-path.ts", "../../../shared/playground/playground.ts", "../../../shared/outline/select.ts", "../../../shared/outline/tree.ts", "../../../shared/table/table.ts", "main.ts"],
- "sourcesContent": ["/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/gogodocs \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/gogodocs\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/gogodocs/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/gogodocs/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/*!\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the playground implementation of the documentation\n// page. The playground involves a \"play\" button that allows you to open up\n// a new link to play.golang.org using the example code.\n\n// The CSS is in static/frontend/unit/main/_doc.css\n\nimport { abs } from '../base-path/base-path';\n\n/**\n * CSS classes used by PlaygroundExampleController\n */\nconst PlayExampleClassName = {\n PLAY_HREF: '.js-exampleHref',\n PLAY_CONTAINER: '.js-exampleContainer',\n EXAMPLE_INPUT: '.Documentation-exampleCode',\n EXAMPLE_OUTPUT: '.Documentation-exampleOutput',\n EXAMPLE_OUTPUT_CONTAINER: '.js-exampleOutputContainer',\n EXAMPLE_ERROR: '.Documentation-exampleError',\n PLAY_BUTTON: '.Documentation-examplePlayButton',\n SHARE_BUTTON: '.Documentation-exampleShareButton',\n FORMAT_BUTTON: '.Documentation-exampleFormatButton',\n RUN_BUTTON: '.Documentation-exampleRunButton',\n};\n\n/**\n * This controller enables playground examples to expand their dropdown or\n * generate shareable Go Playground URLs.\n */\nexport class PlaygroundExampleController {\n /**\n * The anchor tag used to identify the container with an example href.\n * There is only one in an example container div.\n */\n private readonly anchorEl: HTMLAnchorElement | null;\n\n /**\n * The error element\n */\n private readonly errorEl: Element | null;\n\n /**\n * Buttons that redirect to an example's playground, this element\n * only exists in executable examples.\n */\n private readonly playButtonEl: Element | null;\n private readonly shareButtonEl: Element | null;\n\n /**\n * Button that formats the code in an example's playground.\n */\n private readonly formatButtonEl: Element | null;\n\n /**\n * Button that runs the code in an example's playground, this element\n * only exists in executable examples.\n */\n private readonly runButtonEl: Element | null;\n\n /**\n * The executable code of an example.\n */\n private readonly inputEl: HTMLTextAreaElement | null;\n\n /**\n * The output of the given example code. This only exists if the\n * author of the package provides an output for this example.\n */\n private readonly outputEl: Element | null;\n\n /**\n * The container for the output.\n */\n private readonly outputContainerEl: HTMLElement | null;\n\n /**\n * @param exampleEl The div that contains playground content for the given example.\n */\n constructor(private readonly exampleEl: HTMLDetailsElement) {\n this.exampleEl = exampleEl;\n this.anchorEl = exampleEl.querySelector('a');\n this.errorEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_ERROR);\n this.playButtonEl = exampleEl.querySelector(PlayExampleClassName.PLAY_BUTTON);\n this.shareButtonEl = exampleEl.querySelector(PlayExampleClassName.SHARE_BUTTON);\n this.formatButtonEl = exampleEl.querySelector(PlayExampleClassName.FORMAT_BUTTON);\n this.runButtonEl = exampleEl.querySelector(PlayExampleClassName.RUN_BUTTON);\n this.inputEl = this.makeTextArea(exampleEl.querySelector(PlayExampleClassName.EXAMPLE_INPUT));\n this.outputEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT);\n this.outputContainerEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT_CONTAINER);\n\n // This is legacy listener to be replaced the listener for shareButtonEl.\n this.playButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.shareButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.formatButtonEl?.addEventListener('click', () => this.handleFormatButtonClick());\n this.runButtonEl?.addEventListener('click', () => this.handleRunButtonClick());\n\n if (!this.inputEl) return;\n\n this.resize();\n this.inputEl.addEventListener('keyup', () => this.resize());\n this.inputEl.addEventListener('keydown', e => this.onKeydown(e));\n }\n\n /**\n * Replace the pre element with a textarea. The examples are initially rendered\n * as pre elements so they're fully visible when JS is disabled.\n */\n makeTextArea(el: Element | null): HTMLTextAreaElement {\n const t = document.createElement('textarea');\n t.classList.add('Documentation-exampleCode', 'code');\n t.spellcheck = false;\n t.value = el?.textContent ?? '';\n el?.parentElement?.replaceChild(t, el);\n return t;\n }\n\n /**\n * Retrieve the hash value of the anchor element.\n */\n getAnchorHash(): string | undefined {\n return this.anchorEl?.hash;\n }\n\n /**\n * Expands the current playground example.\n */\n expand(): void {\n this.exampleEl.open = true;\n }\n\n /**\n * Resizes the input element to accommodate the amount of text present.\n */\n private resize(): void {\n if (this.inputEl?.value) {\n const numLineBreaks = (this.inputEl.value.match(/\\n/g) || []).length;\n // min-height + lines x line-height + padding + border\n this.inputEl.style.height = `${(20 + numLineBreaks * 20 + 12 + 2) / 16}rem`;\n }\n }\n\n /**\n * Handler to override keyboard behavior in the playground's\n * textarea element.\n *\n * Tab key inserts tabs into the example playground instead of\n * switching to the next interactive element.\n * @param e input element keyboard event.\n */\n private onKeydown(e: KeyboardEvent) {\n if (e.key === 'Tab') {\n document.execCommand('insertText', false, '\\t');\n e.preventDefault();\n }\n }\n\n /**\n * Changes the text of the example's input box.\n */\n private setInputText(output: string) {\n if (this.inputEl) {\n this.inputEl.value = output;\n }\n }\n\n /**\n * Changes the text of the example's output box.\n */\n private setOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent = output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n /**\n * Appends to the text of the example's output box.\n */\n private appendToOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent += output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n private setOutputHTML(output: string) {\n if (this.outputEl) {\n this.outputEl.innerHTML = output;\n }\n }\n\n /**\n * Sets the error message text and overwrites\n * output box to indicate a failed response.\n */\n private setErrorText(err: string) {\n if (this.errorEl) {\n this.errorEl.textContent = err;\n }\n this.setOutputText('An error has occurred\u2026');\n }\n\n private getCodeWithModFile(): string {\n let codeWithModFile = this.inputEl?.value ?? '';\n const moduleVars = document.querySelector('.js-playgroundVars')?.dataset ?? {};\n if (moduleVars.modulepath !== 'std') {\n codeWithModFile = codeWithModFile.concat(`\n-- go.mod --\nmodule play.ground\n\nrequire ${moduleVars.modulepath} ${moduleVars.version}\n`);\n }\n\n return codeWithModFile;\n }\n\n /**\n * Opens a new window to play.golang.org using the\n * example snippet's code in the playground.\n */\n private handleShareButtonClick() {\n const PLAYGROUND_BASE_URL = 'https://play.golang.org/p/';\n\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/share'), {\n method: 'POST',\n body: this.getCodeWithModFile(),\n })\n .then(res => res.text())\n .then(shareId => {\n const href = PLAYGROUND_BASE_URL + shareId;\n this.setOutputHTML(`${href} `);\n window.open(href);\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs gofmt on the example snippet in the playground.\n */\n private handleFormatButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n const body = new FormData();\n body.append('body', this.inputEl?.value ?? '');\n\n fetch(abs('/play/fmt'), {\n method: 'POST',\n body: body,\n })\n .then(res => res.json())\n .then(({ Body, Error }) => {\n this.setOutputText(Error || 'Done.');\n if (Body) {\n this.setInputText(Body);\n this.resize();\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs the code snippet in the example playground.\n */\n private handleRunButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/compile'), {\n method: 'POST',\n body: JSON.stringify({ body: this.getCodeWithModFile(), version: 2 }),\n })\n .then(res => res.json())\n .then(async ({ Events, Errors }) => {\n this.setOutputText(Errors || '');\n for (const e of Events || []) {\n this.appendToOutputText(e.Message);\n await new Promise(resolve => setTimeout(resolve, e.Delay / 1000000));\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n}\n\nexport function initPlaygrounds(): void {\n const exampleHashRegex = location.hash.match(/^#(example-.*)$/);\n if (exampleHashRegex) {\n const exampleHashEl = document.getElementById(exampleHashRegex[1]) as HTMLDetailsElement;\n if (exampleHashEl) {\n exampleHashEl.open = true;\n }\n }\n\n // We use a spread operator to convert a nodelist into an array of elements.\n const exampleHrefs = [\n ...document.querySelectorAll(PlayExampleClassName.PLAY_HREF),\n ];\n\n /**\n * Sometimes exampleHrefs and playContainers are in different order, so we\n * find an exampleHref from a common hash.\n * @param playContainer - playground container\n */\n const findExampleHash = (playContainer: PlaygroundExampleController) =>\n exampleHrefs.find(ex => {\n return ex.hash === playContainer.getAnchorHash();\n });\n\n for (const el of document.querySelectorAll(PlayExampleClassName.PLAY_CONTAINER)) {\n // There should be the same amount of hrefs referencing examples as example containers.\n const playContainer = new PlaygroundExampleController(el as HTMLDetailsElement);\n const exampleHref = findExampleHash(playContainer);\n if (exampleHref) {\n exampleHref.addEventListener('click', () => {\n playContainer.expand();\n });\n } else {\n console.warn('example href not found');\n }\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { TreeNavController } from './tree.js';\n\nexport class SelectNavController {\n constructor(private el: Element) {\n this.el.addEventListener('change', e => {\n const target = e.target as HTMLSelectElement;\n let href = target.value;\n if (!target.value.startsWith('/')) {\n href = '/' + href;\n }\n window.location.href = href;\n });\n }\n}\n\nexport function makeSelectNav(tree: TreeNavController): HTMLLabelElement {\n const label = document.createElement('label');\n label.classList.add('go-Label');\n label.setAttribute('aria-label', 'Menu');\n const select = document.createElement('select');\n select.classList.add('go-Select', 'js-selectNav');\n label.appendChild(select);\n const outline = document.createElement('optgroup');\n outline.label = 'Outline';\n select.appendChild(outline);\n const groupMap: Record = {};\n let group: HTMLOptGroupElement;\n for (const t of tree.treeitems) {\n if (Number(t.depth) > 4) continue;\n if (t.groupTreeitem) {\n group = groupMap[t.groupTreeitem.label];\n if (!group) {\n group = groupMap[t.groupTreeitem.label] = document.createElement('optgroup');\n group.label = t.groupTreeitem.label;\n select.appendChild(group);\n }\n } else {\n group = outline;\n }\n const o = document.createElement('option');\n o.label = t.label;\n o.textContent = t.label;\n o.value = (t.el as HTMLAnchorElement).href.replace(window.location.origin, '').replace('/', '');\n group.appendChild(o);\n }\n tree.addObserver(t => {\n const hash = (t.el as HTMLAnchorElement).hash;\n const value = select.querySelector(`[value$=\"${hash}\"]`)?.value;\n if (value) {\n select.value = value;\n }\n }, 50);\n return label;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * TreeNavController is the navigation tree component of the documentation page.\n * It adds accessiblity attributes to a tree, observes the heading elements\n * focus the topmost link for headings visible on the page, and implements the\n * WAI-ARIA Treeview Design Pattern with full\n * [keyboard support](https://www.w3.org/TR/wai-aria-practices/examples/treeview/treeview-2/treeview-2a.html#kbd_label).\n */\nexport class TreeNavController {\n treeitems: TreeItem[];\n\n /**\n * firstChars is the first character of each treeitem in the same order\n * as this.treeitems. We use this array to set focus by character when\n * navigating the tree with a keyboard.\n */\n private firstChars: string[];\n private firstTreeitem: TreeItem | null;\n private lastTreeitem: TreeItem | null;\n private observerCallbacks: ((t: TreeItem) => void)[];\n\n constructor(private el: HTMLElement) {\n this.treeitems = [];\n this.firstChars = [];\n this.firstTreeitem = null;\n this.lastTreeitem = null;\n this.observerCallbacks = [];\n this.init();\n }\n\n private init(): void {\n this.handleResize();\n window.addEventListener('resize', this.handleResize);\n this.findTreeItems();\n this.updateVisibleTreeitems();\n this.observeTargets();\n if (this.firstTreeitem) {\n this.firstTreeitem.el.tabIndex = 0;\n }\n }\n\n private handleResize = (): void => {\n this.el.style.setProperty('--js-tree-height', '100vh');\n this.el.style.setProperty('--js-tree-height', this.el.clientHeight + 'px');\n };\n\n private observeTargets() {\n this.addObserver(treeitem => {\n this.expandTreeitem(treeitem);\n this.setSelected(treeitem);\n // TODO: Fix scroll issue in https://golang.org/issue/47450.\n // treeitem.el.scrollIntoView({ block: 'nearest' });\n });\n\n const targets = new Map();\n const observer = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n targets.set(entry.target.id, entry.isIntersecting || entry.intersectionRatio === 1);\n }\n for (const [id, isIntersecting] of targets) {\n if (isIntersecting) {\n const active = this.treeitems.find(t =>\n (t.el as HTMLAnchorElement)?.href.endsWith(`#${id}`)\n );\n if (active) {\n for (const fn of this.observerCallbacks) {\n fn(active);\n }\n }\n break;\n }\n }\n },\n {\n threshold: 1.0,\n rootMargin: '-60px 0px 0px 0px',\n }\n );\n\n for (const href of this.treeitems.map(t => t.el.getAttribute('href'))) {\n if (href) {\n const id = href.replace(window.location.origin, '').replace('/', '').replace('#', '');\n const target = document.getElementById(id);\n if (target && !id.startsWith('example-')) {\n observer.observe(target);\n }\n }\n }\n }\n\n addObserver(fn: (t: TreeItem) => void, delay = 200): void {\n this.observerCallbacks.push(debounce(fn, delay));\n }\n\n setFocusToNextItem(currentItem: TreeItem): void {\n let nextItem = null;\n for (let i = currentItem.index + 1; i < this.treeitems.length; i++) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n nextItem = ti;\n break;\n }\n }\n if (nextItem) {\n this.setFocusToItem(nextItem);\n }\n }\n\n setFocusToPreviousItem(currentItem: TreeItem): void {\n let prevItem = null;\n for (let i = currentItem.index - 1; i > -1; i--) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n prevItem = ti;\n break;\n }\n }\n if (prevItem) {\n this.setFocusToItem(prevItem);\n }\n }\n\n setFocusToParentItem(currentItem: TreeItem): void {\n if (currentItem.groupTreeitem) {\n this.setFocusToItem(currentItem.groupTreeitem);\n }\n }\n\n setFocusToFirstItem(): void {\n this.firstTreeitem && this.setFocusToItem(this.firstTreeitem);\n }\n\n setFocusToLastItem(): void {\n this.lastTreeitem && this.setFocusToItem(this.lastTreeitem);\n }\n\n setSelected(currentItem: TreeItem): void {\n for (const l1 of this.el.querySelectorAll('[aria-expanded=\"true\"]')) {\n if (l1 === currentItem.el) continue;\n if (!l1.nextElementSibling?.contains(currentItem.el)) {\n l1.setAttribute('aria-expanded', 'false');\n }\n }\n for (const l1 of this.el.querySelectorAll('[aria-selected]')) {\n if (l1 !== currentItem.el) {\n l1.setAttribute('aria-selected', 'false');\n }\n }\n currentItem.el.setAttribute('aria-selected', 'true');\n this.updateVisibleTreeitems();\n this.setFocusToItem(currentItem, false);\n }\n\n expandTreeitem(treeitem: TreeItem): void {\n let currentItem: TreeItem | null = treeitem;\n while (currentItem) {\n if (currentItem.isExpandable) {\n currentItem.el.setAttribute('aria-expanded', 'true');\n }\n currentItem = currentItem.groupTreeitem;\n }\n this.updateVisibleTreeitems();\n }\n\n expandAllSiblingItems(currentItem: TreeItem): void {\n for (const ti of this.treeitems) {\n if (ti.groupTreeitem === currentItem.groupTreeitem && ti.isExpandable) {\n this.expandTreeitem(ti);\n }\n }\n }\n\n collapseTreeitem(currentItem: TreeItem): void {\n let groupTreeitem = null;\n\n if (currentItem.isExpanded()) {\n groupTreeitem = currentItem;\n } else {\n groupTreeitem = currentItem.groupTreeitem;\n }\n\n if (groupTreeitem) {\n groupTreeitem.el.setAttribute('aria-expanded', 'false');\n this.updateVisibleTreeitems();\n this.setFocusToItem(groupTreeitem);\n }\n }\n\n setFocusByFirstCharacter(currentItem: TreeItem, char: string): void {\n let start: number, index: number;\n char = char.toLowerCase();\n\n // Get start index for search based on position of currentItem\n start = currentItem.index + 1;\n if (start === this.treeitems.length) {\n start = 0;\n }\n\n // Check remaining slots in the menu\n index = this.getIndexFirstChars(start, char);\n\n // If not found in remaining slots, check from beginning\n if (index === -1) {\n index = this.getIndexFirstChars(0, char);\n }\n\n // If match was found...\n if (index > -1) {\n this.setFocusToItem(this.treeitems[index]);\n }\n }\n\n private findTreeItems() {\n const findItems = (el: HTMLElement, group: TreeItem | null) => {\n let ti = group;\n let curr = el.firstElementChild as HTMLElement;\n while (curr) {\n if (curr.tagName === 'A' || curr.tagName === 'SPAN') {\n ti = new TreeItem(curr, this, group);\n this.treeitems.push(ti);\n this.firstChars.push(ti.label.substring(0, 1).toLowerCase());\n }\n if (curr.firstElementChild) {\n findItems(curr, ti);\n }\n curr = curr.nextElementSibling as HTMLElement;\n }\n };\n findItems(this.el as HTMLElement, null);\n this.treeitems.map((ti, idx) => (ti.index = idx));\n }\n\n private updateVisibleTreeitems(): void {\n this.firstTreeitem = this.treeitems[0];\n\n for (const ti of this.treeitems) {\n let parent = ti.groupTreeitem;\n ti.isVisible = true;\n while (parent && parent.el !== this.el) {\n if (!parent.isExpanded()) {\n ti.isVisible = false;\n }\n parent = parent.groupTreeitem;\n }\n if (ti.isVisible) {\n this.lastTreeitem = ti;\n }\n }\n }\n\n private setFocusToItem(treeitem: TreeItem, focusEl = true) {\n treeitem.el.tabIndex = 0;\n if (focusEl) {\n treeitem.el.focus();\n }\n for (const ti of this.treeitems) {\n if (ti !== treeitem) {\n ti.el.tabIndex = -1;\n }\n }\n }\n\n private getIndexFirstChars(startIndex: number, char: string): number {\n for (let i = startIndex; i < this.firstChars.length; i++) {\n if (this.treeitems[i].isVisible && char === this.firstChars[i]) {\n return i;\n }\n }\n return -1;\n }\n}\n\nclass TreeItem {\n el: HTMLElement;\n groupTreeitem: TreeItem | null;\n label: string;\n isExpandable: boolean;\n isVisible: boolean;\n depth: number;\n index: number;\n\n private tree: TreeNavController;\n private isInGroup: boolean;\n\n constructor(el: HTMLElement, treeObj: TreeNavController, group: TreeItem | null) {\n el.tabIndex = -1;\n this.el = el;\n this.groupTreeitem = group;\n this.label = el.textContent?.trim() ?? '';\n this.tree = treeObj;\n this.depth = (group?.depth || 0) + 1;\n this.index = 0;\n\n const parent = el.parentElement;\n if (parent?.tagName.toLowerCase() === 'li') {\n parent?.setAttribute('role', 'none');\n }\n el.setAttribute('aria-level', this.depth + '');\n if (el.getAttribute('aria-label')) {\n this.label = el?.getAttribute('aria-label')?.trim() ?? '';\n }\n\n this.isExpandable = false;\n this.isVisible = false;\n this.isInGroup = !!group;\n\n let curr = el.nextElementSibling;\n while (curr) {\n if (curr.tagName.toLowerCase() == 'ul') {\n const groupId = `${group?.label ?? ''} nav group ${this.label}`.replace(/[\\W_]+/g, '_');\n el.setAttribute('aria-owns', groupId);\n el.setAttribute('aria-expanded', 'false');\n curr.setAttribute('role', 'group');\n curr.setAttribute('id', groupId);\n this.isExpandable = true;\n break;\n }\n\n curr = curr.nextElementSibling;\n }\n this.init();\n }\n\n private init() {\n this.el.tabIndex = -1;\n if (!this.el.getAttribute('role')) {\n this.el.setAttribute('role', 'treeitem');\n }\n this.el.addEventListener('keydown', this.handleKeydown.bind(this));\n this.el.addEventListener('click', this.handleClick.bind(this));\n this.el.addEventListener('focus', this.handleFocus.bind(this));\n this.el.addEventListener('blur', this.handleBlur.bind(this));\n }\n\n isExpanded() {\n if (this.isExpandable) {\n return this.el.getAttribute('aria-expanded') === 'true';\n }\n\n return false;\n }\n\n isSelected() {\n return this.el.getAttribute('aria-selected') === 'true';\n }\n\n private handleClick(event: MouseEvent) {\n // only process click events that directly happened on this treeitem\n if (event.target !== this.el && event.target !== this.el.firstElementChild) {\n return;\n }\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n }\n\n private handleFocus() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.add('focus');\n }\n\n private handleBlur() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.remove('focus');\n }\n\n private handleKeydown(event: KeyboardEvent) {\n if (event.altKey || event.ctrlKey || event.metaKey) {\n return;\n }\n\n let captured = false;\n switch (event.key) {\n case ' ':\n case 'Enter':\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n captured = true;\n } else {\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n break;\n\n case 'ArrowUp':\n this.tree.setFocusToPreviousItem(this);\n captured = true;\n break;\n\n case 'ArrowDown':\n this.tree.setFocusToNextItem(this);\n captured = true;\n break;\n\n case 'ArrowRight':\n if (this.isExpandable) {\n if (this.isExpanded()) {\n this.tree.setFocusToNextItem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n }\n captured = true;\n break;\n\n case 'ArrowLeft':\n if (this.isExpandable && this.isExpanded()) {\n this.tree.collapseTreeitem(this);\n captured = true;\n } else {\n if (this.isInGroup) {\n this.tree.setFocusToParentItem(this);\n captured = true;\n }\n }\n break;\n\n case 'Home':\n this.tree.setFocusToFirstItem();\n captured = true;\n break;\n\n case 'End':\n this.tree.setFocusToLastItem();\n captured = true;\n break;\n\n default:\n if (event.key.length === 1 && event.key.match(/\\S/)) {\n if (event.key == '*') {\n this.tree.expandAllSiblingItems(this);\n } else {\n this.tree.setFocusByFirstCharacter(this, event.key);\n }\n captured = true;\n }\n break;\n }\n\n if (captured) {\n event.stopPropagation();\n event.preventDefault();\n }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction debounce any>(func: T, wait: number) {\n let timeout: ReturnType | null;\n return (...args: Parameters) => {\n const later = () => {\n timeout = null;\n func(...args);\n };\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(later, wait);\n };\n}\n", "/*!\n * @license\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * Controller for a table element with expandable rows. Adds event listeners to\n * a toggle within a table row that controls visiblity of additional related\n * rows in the table.\n *\n * @example\n * ```typescript\n * import {ExpandableRowsTableController} from '/static/js/table';\n *\n * const el = document .querySelector('.js-myTableElement')\n * new ExpandableRowsTableController(el));\n * ```\n */\nexport class ExpandableRowsTableController {\n private rows: HTMLTableRowElement[];\n private toggles: HTMLButtonElement[];\n\n /**\n * Create a table controller.\n * @param table - The table element to which the controller binds.\n */\n constructor(private table: HTMLTableElement, private toggleAll?: HTMLButtonElement | null) {\n this.rows = Array.from(table.querySelectorAll('[data-aria-controls]'));\n this.toggles = Array.from(this.table.querySelectorAll('[aria-expanded]'));\n this.setAttributes();\n this.attachEventListeners();\n this.update();\n }\n\n /**\n * setAttributes sets data-aria-* and data-id attributes to regular\n * html attributes as a workaround for limitations from safehtml.\n */\n private setAttributes() {\n for (const a of ['data-aria-controls', 'data-aria-labelledby', 'data-id']) {\n this.table.querySelectorAll(`[${a}]`).forEach(t => {\n t.setAttribute(a.replace('data-', ''), t.getAttribute(a) ?? '');\n t.removeAttribute(a);\n });\n }\n }\n\n private attachEventListeners() {\n this.rows.forEach(t => {\n t.addEventListener('click', e => {\n this.handleToggleClick(e);\n });\n });\n this.toggleAll?.addEventListener('click', () => {\n this.expandAllItems();\n });\n\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n this.expandAllItems();\n }\n });\n }\n\n private handleToggleClick(e: MouseEvent) {\n let target = e.currentTarget as HTMLTableRowElement | null;\n if (!target?.hasAttribute('aria-expanded')) {\n target = this.table.querySelector(\n `button[aria-controls=\"${target?.getAttribute('aria-controls')}\"]`\n );\n }\n const isExpanded = target?.getAttribute('aria-expanded') === 'true';\n target?.setAttribute('aria-expanded', isExpanded ? 'false' : 'true');\n e.stopPropagation();\n this.update();\n }\n\n expandAllItems = (): void => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'true'));\n this.update();\n };\n\n private collapseAllItems = () => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'false'));\n this.update();\n };\n\n private update = () => {\n this.updateVisibleItems();\n setTimeout(() => this.updateGlobalToggle());\n };\n\n private updateVisibleItems() {\n this.rows.map(t => {\n const isExpanded = t?.getAttribute('aria-expanded') === 'true';\n const rowIds = t?.getAttribute('aria-controls')?.trimEnd().split(' ');\n rowIds?.map(id => {\n const target = document.getElementById(`${id}`);\n if (isExpanded) {\n target?.classList.add('visible');\n target?.classList.remove('hidden');\n } else {\n target?.classList.add('hidden');\n target?.classList.remove('visible');\n }\n });\n });\n }\n\n private updateGlobalToggle() {\n if (!this.toggleAll) return;\n if (this.rows.some(t => t.hasAttribute('aria-expanded'))) {\n this.toggleAll.style.display = 'block';\n }\n const someCollapsed = this.toggles.some(el => el.getAttribute('aria-expanded') === 'false');\n if (someCollapsed) {\n this.toggleAll.innerText = 'Expand all';\n this.toggleAll.onclick = this.expandAllItems;\n this.toggleAll.setAttribute('aria-label', 'Expand all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n } else {\n this.toggleAll.innerText = 'Collapse all';\n this.toggleAll.onclick = this.collapseAllItems;\n this.toggleAll.setAttribute('aria-label', 'Collapse all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n }\n }\n}\n", "import { initPlaygrounds } from 'static/shared/playground/playground';\nimport { SelectNavController, makeSelectNav } from 'static/shared/outline/select';\nimport { TreeNavController } from 'static/shared/outline/tree';\nimport { ExpandableRowsTableController } from 'static/shared/table/table';\n\ninitPlaygrounds();\n\nconst directories = document.querySelector('.js-expandableTable');\nif (directories) {\n const table = new ExpandableRowsTableController(\n directories,\n document.querySelector('.js-expandAllDirectories')\n );\n // Expand directories on page load with expand-directories query param.\n if (window.location.search.includes('expand-directories')) {\n table.expandAllItems();\n }\n\n const internalToggle = document.querySelector('.js-showInternalDirectories');\n if (internalToggle) {\n if (document.querySelector('.UnitDirectories-internal')) {\n internalToggle.style.display = 'block';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n }\n internalToggle.addEventListener('click', () => {\n if (directories.classList.contains('UnitDirectories-showInternal')) {\n directories.classList.remove('UnitDirectories-showInternal');\n internalToggle.innerText = 'Show internal';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n } else {\n directories.classList.add('UnitDirectories-showInternal');\n internalToggle.innerText = 'Hide internal';\n internalToggle.setAttribute('aria-label', 'Hide Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'hideInternal-description');\n }\n });\n }\n if (document.querySelector('html[data-local=\"true\"]')) {\n internalToggle?.click();\n }\n}\n\nconst treeEl = document.querySelector('.js-tree');\nif (treeEl) {\n const treeCtrl = new TreeNavController(treeEl);\n const select = makeSelectNav(treeCtrl);\n const mobileNav = document.querySelector('.js-mainNavMobile');\n if (mobileNav && mobileNav.firstElementChild) {\n mobileNav?.replaceChild(select, mobileNav.firstElementChild);\n }\n if (select.firstElementChild) {\n new SelectNavController(select.firstElementChild);\n }\n}\n\n/**\n * Event handlers for expanding and collapsing the readme section.\n */\nconst readme = document.querySelector('.js-readme');\nconst readmeContent = document.querySelector('.js-readmeContent');\nconst readmeOutline = document.querySelector('.js-readmeOutline');\nconst readmeExpand = document.querySelectorAll('.js-readmeExpand');\nconst readmeCollapse = document.querySelector('.js-readmeCollapse');\nconst mobileNavSelect = document.querySelector('.DocNavMobile-select');\nif (readme && readmeContent && readmeOutline && readmeExpand.length && readmeCollapse) {\n if (readme.clientHeight > 320) {\n readme?.classList.remove('UnitReadme--expanded');\n readme?.classList.add('UnitReadme--toggle');\n }\n if (window.location.hash.includes('readme')) {\n expandReadme();\n }\n mobileNavSelect?.addEventListener('change', e => {\n if ((e.target as HTMLSelectElement).value.startsWith('readme-')) {\n expandReadme();\n }\n });\n readmeExpand.forEach(el =>\n el.addEventListener('click', e => {\n e.preventDefault();\n expandReadme();\n readme.scrollIntoView();\n })\n );\n readmeCollapse.addEventListener('click', e => {\n e.preventDefault();\n readme.classList.remove('UnitReadme--expanded');\n if (readmeExpand[1]) {\n readmeExpand[1].scrollIntoView({ block: 'center' });\n }\n });\n readmeContent.addEventListener('keyup', () => {\n expandReadme();\n });\n readmeContent.addEventListener('click', () => {\n expandReadme();\n });\n readmeOutline.addEventListener('click', () => {\n expandReadme();\n });\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n expandReadme();\n }\n });\n}\n\n/**\n * expandReadme expands the readme and adds the section-readme hash to the\n * URL so it stays expanded when navigating back from an external link.\n */\nfunction expandReadme() {\n history.replaceState(null, '', `${location.pathname}${location.search}#section-readme`);\n readme?.classList.add('UnitReadme--expanded');\n}\n\n/**\n * Expand details items that are focused. This will expand\n * deprecated symbols when they are navigated to from the index\n * or a direct link.\n */\nfunction openDeprecatedSymbol() {\n if (!location.hash) return;\n const heading = document.getElementById(location.hash.slice(1));\n const grandParent = heading?.parentElement?.parentElement as HTMLDetailsElement | null;\n if (grandParent?.nodeName === 'DETAILS') {\n grandParent.open = true;\n }\n}\nopenDeprecatedSymbol();\nwindow.addEventListener('hashchange', () => openDeprecatedSymbol());\n\n/**\n * Listen for changes in the build context dropdown.\n */\ndocument.querySelectorAll('.js-buildContextSelect').forEach(el => {\n el.addEventListener('change', e => {\n window.location.search = `?GOOS=${(e.target as HTMLSelectElement).value}`;\n });\n});\n\n/**\n * fork\uFF1Aunexported\uFF08\u79C1\u6709\uFF09\u7B26\u53F7 toggle\u3002\n *\n * \u80CC\u666F\uFF1Apkgsite -show-unexported flag \u8BA9 godoc \u628A\u79C1\u6709 type/func/method\n * \u90FD\u6E32\u5230 page\u3002\u4F46\u8BFB\u8005\u5927\u591A\u6570\u65F6\u5019\u53EA\u5173\u5FC3 public API\uFF0C\u79C1\u6709\u7684\u592A\u591A\u53CD\u800C\u62D6\u6162\n * \u9605\u8BFB\u3002\u8FD9\u5C42\u5728 client \u7AEF\u6309 id \u9996\u5B57\u6BCD\u5927\u5C0F\u5199\u81EA\u52A8 hide \u79C1\u6709 declaration +\n * index \u94FE\u63A5\uFF0C\u518D\u6CE8\u5165\u4E00\u4E2A toggle button \u4E00\u952E\u5207\u663E\u793A\u3002\u72B6\u6001\u7528 localStorage\n * \u8BB0\u4E0B\uFF0C\u8DE8\u9875\u4FDD\u7559\u3002\n */\n(() => {\n if (!document.querySelector('h4[data-kind]')) return; // \u975E godoc \u8BE6\u60C5\u9875\n\n // method id \u5F62\u5982 \"Type.method\"\uFF0C\u53D6\u6700\u540E\u6BB5\u5224\u79C1\u6709\uFF1B\u5176\u4ED6\u76F4\u63A5\u5224 id \u672C\u8EAB\u3002\n const isUnexported = (id: string): boolean => {\n const last = id.split('.').pop() ?? id;\n return /^[a-z]/.test(last);\n };\n\n // \u6807 declaration wrapper\uFF1Afunc \u5305\u5728 .Documentation-function\uFF1Btype / method\n // \u5305\u5728 .Documentation-type / .Documentation-typeFunc / .Documentation-typeMethod\u3002\n document.querySelectorAll('h4[data-kind][id]').forEach(h => {\n if (!isUnexported(h.id)) return;\n const wrapper = h.closest(\n '.Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod'\n );\n wrapper?.classList.add('Documentation-unexported');\n });\n\n // index \u5217\u8868\u9879\u4E5F\u6309\u94FE\u63A5\u9996\u5B57\u6BCD\u5224\n document\n .querySelectorAll(\n '.Documentation-indexFunction a[href^=\"#\"], ' +\n '.Documentation-indexType a[href^=\"#\"], ' +\n '.Documentation-indexTypeFunctions a[href^=\"#\"], ' +\n '.Documentation-indexTypeMethods a[href^=\"#\"]'\n )\n .forEach(a => {\n if (isUnexported(a.getAttribute('href')!.slice(1))) {\n a.closest('li')?.classList.add('Documentation-unexported');\n }\n });\n\n // \u6CE8\u5165 CSS\uFF08\u4E0D\u52A8 main.css build pipeline\uFF0C\u907F\u514D\u589E\u91CF\u6539 esbuild \u8F93\u51FA\uFF09\n const style = document.createElement('style');\n style.textContent =\n 'body:not(.show-unexported) .Documentation-unexported{display:none}';\n document.head.appendChild(style);\n\n // \u6CE8\u5165 toggle button\u2014\u2014\u653E Index \u6807\u9898\u65C1\u8FB9\u6700\u663E\u773C\uFF0C\u8DDF \"Show internal\" \u540C\u4F4D\n const indexHeader = document.querySelector('#pkg-index');\n if (!indexHeader) return;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'go-Button go-Button--inline';\n btn.style.marginLeft = '0.75rem';\n btn.style.fontSize = '0.875rem';\n btn.style.verticalAlign = 'middle';\n\n const STORE_KEY = 'gogodocs:showUnexported';\n const apply = (show: boolean) => {\n document.body.classList.toggle('show-unexported', show);\n btn.textContent = show ? 'Hide unexported' : 'Show unexported';\n try {\n localStorage.setItem(STORE_KEY, show ? '1' : '0');\n } catch {\n /* localStorage \u4E0D\u53EF\u7528\uFF08\u9690\u79C1\u6A21\u5F0F / \u6587\u4EF6\u534F\u8BAE\uFF09\u65F6\u5FFD\u7565\uFF0C\u53EA\u4E22\u5931\u8DE8\u9875\u8BB0\u5FC6 */\n }\n };\n\n apply(localStorage.getItem(STORE_KEY) === '1');\n btn.addEventListener('click', () =>\n apply(!document.body.classList.contains('show-unexported'))\n );\n indexHeader.appendChild(btn);\n})();\n"],
- "mappings": "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",
+ "sourcesContent": ["/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/gogodocs \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/gogodocs\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/gogodocs/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/gogodocs/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/*!\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the playground implementation of the documentation\n// page. The playground involves a \"play\" button that allows you to open up\n// a new link to play.golang.org using the example code.\n\n// The CSS is in static/frontend/unit/main/_doc.css\n\nimport { abs } from '../base-path/base-path';\n\n/**\n * CSS classes used by PlaygroundExampleController\n */\nconst PlayExampleClassName = {\n PLAY_HREF: '.js-exampleHref',\n PLAY_CONTAINER: '.js-exampleContainer',\n EXAMPLE_INPUT: '.Documentation-exampleCode',\n EXAMPLE_OUTPUT: '.Documentation-exampleOutput',\n EXAMPLE_OUTPUT_CONTAINER: '.js-exampleOutputContainer',\n EXAMPLE_ERROR: '.Documentation-exampleError',\n PLAY_BUTTON: '.Documentation-examplePlayButton',\n SHARE_BUTTON: '.Documentation-exampleShareButton',\n FORMAT_BUTTON: '.Documentation-exampleFormatButton',\n RUN_BUTTON: '.Documentation-exampleRunButton',\n};\n\n/**\n * This controller enables playground examples to expand their dropdown or\n * generate shareable Go Playground URLs.\n */\nexport class PlaygroundExampleController {\n /**\n * The anchor tag used to identify the container with an example href.\n * There is only one in an example container div.\n */\n private readonly anchorEl: HTMLAnchorElement | null;\n\n /**\n * The error element\n */\n private readonly errorEl: Element | null;\n\n /**\n * Buttons that redirect to an example's playground, this element\n * only exists in executable examples.\n */\n private readonly playButtonEl: Element | null;\n private readonly shareButtonEl: Element | null;\n\n /**\n * Button that formats the code in an example's playground.\n */\n private readonly formatButtonEl: Element | null;\n\n /**\n * Button that runs the code in an example's playground, this element\n * only exists in executable examples.\n */\n private readonly runButtonEl: Element | null;\n\n /**\n * The executable code of an example.\n */\n private readonly inputEl: HTMLTextAreaElement | null;\n\n /**\n * The output of the given example code. This only exists if the\n * author of the package provides an output for this example.\n */\n private readonly outputEl: Element | null;\n\n /**\n * The container for the output.\n */\n private readonly outputContainerEl: HTMLElement | null;\n\n /**\n * @param exampleEl The div that contains playground content for the given example.\n */\n constructor(private readonly exampleEl: HTMLDetailsElement) {\n this.exampleEl = exampleEl;\n this.anchorEl = exampleEl.querySelector('a');\n this.errorEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_ERROR);\n this.playButtonEl = exampleEl.querySelector(PlayExampleClassName.PLAY_BUTTON);\n this.shareButtonEl = exampleEl.querySelector(PlayExampleClassName.SHARE_BUTTON);\n this.formatButtonEl = exampleEl.querySelector(PlayExampleClassName.FORMAT_BUTTON);\n this.runButtonEl = exampleEl.querySelector(PlayExampleClassName.RUN_BUTTON);\n this.inputEl = this.makeTextArea(exampleEl.querySelector(PlayExampleClassName.EXAMPLE_INPUT));\n this.outputEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT);\n this.outputContainerEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT_CONTAINER);\n\n // This is legacy listener to be replaced the listener for shareButtonEl.\n this.playButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.shareButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.formatButtonEl?.addEventListener('click', () => this.handleFormatButtonClick());\n this.runButtonEl?.addEventListener('click', () => this.handleRunButtonClick());\n\n if (!this.inputEl) return;\n\n this.resize();\n this.inputEl.addEventListener('keyup', () => this.resize());\n this.inputEl.addEventListener('keydown', e => this.onKeydown(e));\n }\n\n /**\n * Replace the pre element with a textarea. The examples are initially rendered\n * as pre elements so they're fully visible when JS is disabled.\n */\n makeTextArea(el: Element | null): HTMLTextAreaElement {\n const t = document.createElement('textarea');\n t.classList.add('Documentation-exampleCode', 'code');\n t.spellcheck = false;\n t.value = el?.textContent ?? '';\n el?.parentElement?.replaceChild(t, el);\n return t;\n }\n\n /**\n * Retrieve the hash value of the anchor element.\n */\n getAnchorHash(): string | undefined {\n return this.anchorEl?.hash;\n }\n\n /**\n * Expands the current playground example.\n */\n expand(): void {\n this.exampleEl.open = true;\n }\n\n /**\n * Resizes the input element to accommodate the amount of text present.\n */\n private resize(): void {\n if (this.inputEl?.value) {\n const numLineBreaks = (this.inputEl.value.match(/\\n/g) || []).length;\n // min-height + lines x line-height + padding + border\n this.inputEl.style.height = `${(20 + numLineBreaks * 20 + 12 + 2) / 16}rem`;\n }\n }\n\n /**\n * Handler to override keyboard behavior in the playground's\n * textarea element.\n *\n * Tab key inserts tabs into the example playground instead of\n * switching to the next interactive element.\n * @param e input element keyboard event.\n */\n private onKeydown(e: KeyboardEvent) {\n if (e.key === 'Tab') {\n document.execCommand('insertText', false, '\\t');\n e.preventDefault();\n }\n }\n\n /**\n * Changes the text of the example's input box.\n */\n private setInputText(output: string) {\n if (this.inputEl) {\n this.inputEl.value = output;\n }\n }\n\n /**\n * Changes the text of the example's output box.\n */\n private setOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent = output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n /**\n * Appends to the text of the example's output box.\n */\n private appendToOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent += output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n private setOutputHTML(output: string) {\n if (this.outputEl) {\n this.outputEl.innerHTML = output;\n }\n }\n\n /**\n * Sets the error message text and overwrites\n * output box to indicate a failed response.\n */\n private setErrorText(err: string) {\n if (this.errorEl) {\n this.errorEl.textContent = err;\n }\n this.setOutputText('An error has occurred\u2026');\n }\n\n private getCodeWithModFile(): string {\n let codeWithModFile = this.inputEl?.value ?? '';\n const moduleVars = document.querySelector('.js-playgroundVars')?.dataset ?? {};\n if (moduleVars.modulepath !== 'std') {\n codeWithModFile = codeWithModFile.concat(`\n-- go.mod --\nmodule play.ground\n\nrequire ${moduleVars.modulepath} ${moduleVars.version}\n`);\n }\n\n return codeWithModFile;\n }\n\n /**\n * Opens a new window to play.golang.org using the\n * example snippet's code in the playground.\n */\n private handleShareButtonClick() {\n const PLAYGROUND_BASE_URL = 'https://play.golang.org/p/';\n\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/share'), {\n method: 'POST',\n body: this.getCodeWithModFile(),\n })\n .then(res => res.text())\n .then(shareId => {\n const href = PLAYGROUND_BASE_URL + shareId;\n this.setOutputHTML(`${href} `);\n window.open(href);\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs gofmt on the example snippet in the playground.\n */\n private handleFormatButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n const body = new FormData();\n body.append('body', this.inputEl?.value ?? '');\n\n fetch(abs('/play/fmt'), {\n method: 'POST',\n body: body,\n })\n .then(res => res.json())\n .then(({ Body, Error }) => {\n this.setOutputText(Error || 'Done.');\n if (Body) {\n this.setInputText(Body);\n this.resize();\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs the code snippet in the example playground.\n */\n private handleRunButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/compile'), {\n method: 'POST',\n body: JSON.stringify({ body: this.getCodeWithModFile(), version: 2 }),\n })\n .then(res => res.json())\n .then(async ({ Events, Errors }) => {\n this.setOutputText(Errors || '');\n for (const e of Events || []) {\n this.appendToOutputText(e.Message);\n await new Promise(resolve => setTimeout(resolve, e.Delay / 1000000));\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n}\n\nexport function initPlaygrounds(): void {\n const exampleHashRegex = location.hash.match(/^#(example-.*)$/);\n if (exampleHashRegex) {\n const exampleHashEl = document.getElementById(exampleHashRegex[1]) as HTMLDetailsElement;\n if (exampleHashEl) {\n exampleHashEl.open = true;\n }\n }\n\n // We use a spread operator to convert a nodelist into an array of elements.\n const exampleHrefs = [\n ...document.querySelectorAll(PlayExampleClassName.PLAY_HREF),\n ];\n\n /**\n * Sometimes exampleHrefs and playContainers are in different order, so we\n * find an exampleHref from a common hash.\n * @param playContainer - playground container\n */\n const findExampleHash = (playContainer: PlaygroundExampleController) =>\n exampleHrefs.find(ex => {\n return ex.hash === playContainer.getAnchorHash();\n });\n\n for (const el of document.querySelectorAll(PlayExampleClassName.PLAY_CONTAINER)) {\n // There should be the same amount of hrefs referencing examples as example containers.\n const playContainer = new PlaygroundExampleController(el as HTMLDetailsElement);\n const exampleHref = findExampleHash(playContainer);\n if (exampleHref) {\n exampleHref.addEventListener('click', () => {\n playContainer.expand();\n });\n } else {\n console.warn('example href not found');\n }\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { TreeNavController } from './tree.js';\n\nexport class SelectNavController {\n constructor(private el: Element) {\n this.el.addEventListener('change', e => {\n const target = e.target as HTMLSelectElement;\n let href = target.value;\n if (!target.value.startsWith('/')) {\n href = '/' + href;\n }\n window.location.href = href;\n });\n }\n}\n\nexport function makeSelectNav(tree: TreeNavController): HTMLLabelElement {\n const label = document.createElement('label');\n label.classList.add('go-Label');\n label.setAttribute('aria-label', 'Menu');\n const select = document.createElement('select');\n select.classList.add('go-Select', 'js-selectNav');\n label.appendChild(select);\n const outline = document.createElement('optgroup');\n outline.label = 'Outline';\n select.appendChild(outline);\n const groupMap: Record = {};\n let group: HTMLOptGroupElement;\n for (const t of tree.treeitems) {\n if (Number(t.depth) > 4) continue;\n if (t.groupTreeitem) {\n group = groupMap[t.groupTreeitem.label];\n if (!group) {\n group = groupMap[t.groupTreeitem.label] = document.createElement('optgroup');\n group.label = t.groupTreeitem.label;\n select.appendChild(group);\n }\n } else {\n group = outline;\n }\n const o = document.createElement('option');\n o.label = t.label;\n o.textContent = t.label;\n o.value = (t.el as HTMLAnchorElement).href.replace(window.location.origin, '').replace('/', '');\n group.appendChild(o);\n }\n tree.addObserver(t => {\n const hash = (t.el as HTMLAnchorElement).hash;\n const value = select.querySelector(`[value$=\"${hash}\"]`)?.value;\n if (value) {\n select.value = value;\n }\n }, 50);\n return label;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * TreeNavController is the navigation tree component of the documentation page.\n * It adds accessiblity attributes to a tree, observes the heading elements\n * focus the topmost link for headings visible on the page, and implements the\n * WAI-ARIA Treeview Design Pattern with full\n * [keyboard support](https://www.w3.org/TR/wai-aria-practices/examples/treeview/treeview-2/treeview-2a.html#kbd_label).\n */\nexport class TreeNavController {\n treeitems: TreeItem[];\n\n /**\n * firstChars is the first character of each treeitem in the same order\n * as this.treeitems. We use this array to set focus by character when\n * navigating the tree with a keyboard.\n */\n private firstChars: string[];\n private firstTreeitem: TreeItem | null;\n private lastTreeitem: TreeItem | null;\n private observerCallbacks: ((t: TreeItem) => void)[];\n\n constructor(private el: HTMLElement) {\n this.treeitems = [];\n this.firstChars = [];\n this.firstTreeitem = null;\n this.lastTreeitem = null;\n this.observerCallbacks = [];\n this.init();\n }\n\n private init(): void {\n this.handleResize();\n window.addEventListener('resize', this.handleResize);\n this.findTreeItems();\n this.updateVisibleTreeitems();\n this.observeTargets();\n if (this.firstTreeitem) {\n this.firstTreeitem.el.tabIndex = 0;\n }\n }\n\n private handleResize = (): void => {\n this.el.style.setProperty('--js-tree-height', '100vh');\n this.el.style.setProperty('--js-tree-height', this.el.clientHeight + 'px');\n };\n\n private observeTargets() {\n this.addObserver(treeitem => {\n this.expandTreeitem(treeitem);\n this.setSelected(treeitem);\n // TODO: Fix scroll issue in https://golang.org/issue/47450.\n // treeitem.el.scrollIntoView({ block: 'nearest' });\n });\n\n const targets = new Map();\n const observer = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n targets.set(entry.target.id, entry.isIntersecting || entry.intersectionRatio === 1);\n }\n for (const [id, isIntersecting] of targets) {\n if (isIntersecting) {\n const active = this.treeitems.find(t =>\n (t.el as HTMLAnchorElement)?.href.endsWith(`#${id}`)\n );\n if (active) {\n for (const fn of this.observerCallbacks) {\n fn(active);\n }\n }\n break;\n }\n }\n },\n {\n threshold: 1.0,\n rootMargin: '-60px 0px 0px 0px',\n }\n );\n\n for (const href of this.treeitems.map(t => t.el.getAttribute('href'))) {\n if (href) {\n const id = href.replace(window.location.origin, '').replace('/', '').replace('#', '');\n const target = document.getElementById(id);\n if (target && !id.startsWith('example-')) {\n observer.observe(target);\n }\n }\n }\n }\n\n addObserver(fn: (t: TreeItem) => void, delay = 200): void {\n this.observerCallbacks.push(debounce(fn, delay));\n }\n\n setFocusToNextItem(currentItem: TreeItem): void {\n let nextItem = null;\n for (let i = currentItem.index + 1; i < this.treeitems.length; i++) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n nextItem = ti;\n break;\n }\n }\n if (nextItem) {\n this.setFocusToItem(nextItem);\n }\n }\n\n setFocusToPreviousItem(currentItem: TreeItem): void {\n let prevItem = null;\n for (let i = currentItem.index - 1; i > -1; i--) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n prevItem = ti;\n break;\n }\n }\n if (prevItem) {\n this.setFocusToItem(prevItem);\n }\n }\n\n setFocusToParentItem(currentItem: TreeItem): void {\n if (currentItem.groupTreeitem) {\n this.setFocusToItem(currentItem.groupTreeitem);\n }\n }\n\n setFocusToFirstItem(): void {\n this.firstTreeitem && this.setFocusToItem(this.firstTreeitem);\n }\n\n setFocusToLastItem(): void {\n this.lastTreeitem && this.setFocusToItem(this.lastTreeitem);\n }\n\n setSelected(currentItem: TreeItem): void {\n for (const l1 of this.el.querySelectorAll('[aria-expanded=\"true\"]')) {\n if (l1 === currentItem.el) continue;\n if (!l1.nextElementSibling?.contains(currentItem.el)) {\n l1.setAttribute('aria-expanded', 'false');\n }\n }\n for (const l1 of this.el.querySelectorAll('[aria-selected]')) {\n if (l1 !== currentItem.el) {\n l1.setAttribute('aria-selected', 'false');\n }\n }\n currentItem.el.setAttribute('aria-selected', 'true');\n this.updateVisibleTreeitems();\n this.setFocusToItem(currentItem, false);\n }\n\n expandTreeitem(treeitem: TreeItem): void {\n let currentItem: TreeItem | null = treeitem;\n while (currentItem) {\n if (currentItem.isExpandable) {\n currentItem.el.setAttribute('aria-expanded', 'true');\n }\n currentItem = currentItem.groupTreeitem;\n }\n this.updateVisibleTreeitems();\n }\n\n expandAllSiblingItems(currentItem: TreeItem): void {\n for (const ti of this.treeitems) {\n if (ti.groupTreeitem === currentItem.groupTreeitem && ti.isExpandable) {\n this.expandTreeitem(ti);\n }\n }\n }\n\n collapseTreeitem(currentItem: TreeItem): void {\n let groupTreeitem = null;\n\n if (currentItem.isExpanded()) {\n groupTreeitem = currentItem;\n } else {\n groupTreeitem = currentItem.groupTreeitem;\n }\n\n if (groupTreeitem) {\n groupTreeitem.el.setAttribute('aria-expanded', 'false');\n this.updateVisibleTreeitems();\n this.setFocusToItem(groupTreeitem);\n }\n }\n\n setFocusByFirstCharacter(currentItem: TreeItem, char: string): void {\n let start: number, index: number;\n char = char.toLowerCase();\n\n // Get start index for search based on position of currentItem\n start = currentItem.index + 1;\n if (start === this.treeitems.length) {\n start = 0;\n }\n\n // Check remaining slots in the menu\n index = this.getIndexFirstChars(start, char);\n\n // If not found in remaining slots, check from beginning\n if (index === -1) {\n index = this.getIndexFirstChars(0, char);\n }\n\n // If match was found...\n if (index > -1) {\n this.setFocusToItem(this.treeitems[index]);\n }\n }\n\n private findTreeItems() {\n const findItems = (el: HTMLElement, group: TreeItem | null) => {\n let ti = group;\n let curr = el.firstElementChild as HTMLElement;\n while (curr) {\n if (curr.tagName === 'A' || curr.tagName === 'SPAN') {\n ti = new TreeItem(curr, this, group);\n this.treeitems.push(ti);\n this.firstChars.push(ti.label.substring(0, 1).toLowerCase());\n }\n if (curr.firstElementChild) {\n findItems(curr, ti);\n }\n curr = curr.nextElementSibling as HTMLElement;\n }\n };\n findItems(this.el as HTMLElement, null);\n this.treeitems.map((ti, idx) => (ti.index = idx));\n }\n\n private updateVisibleTreeitems(): void {\n this.firstTreeitem = this.treeitems[0];\n\n for (const ti of this.treeitems) {\n let parent = ti.groupTreeitem;\n ti.isVisible = true;\n while (parent && parent.el !== this.el) {\n if (!parent.isExpanded()) {\n ti.isVisible = false;\n }\n parent = parent.groupTreeitem;\n }\n if (ti.isVisible) {\n this.lastTreeitem = ti;\n }\n }\n }\n\n private setFocusToItem(treeitem: TreeItem, focusEl = true) {\n treeitem.el.tabIndex = 0;\n if (focusEl) {\n treeitem.el.focus();\n }\n for (const ti of this.treeitems) {\n if (ti !== treeitem) {\n ti.el.tabIndex = -1;\n }\n }\n }\n\n private getIndexFirstChars(startIndex: number, char: string): number {\n for (let i = startIndex; i < this.firstChars.length; i++) {\n if (this.treeitems[i].isVisible && char === this.firstChars[i]) {\n return i;\n }\n }\n return -1;\n }\n}\n\nclass TreeItem {\n el: HTMLElement;\n groupTreeitem: TreeItem | null;\n label: string;\n isExpandable: boolean;\n isVisible: boolean;\n depth: number;\n index: number;\n\n private tree: TreeNavController;\n private isInGroup: boolean;\n\n constructor(el: HTMLElement, treeObj: TreeNavController, group: TreeItem | null) {\n el.tabIndex = -1;\n this.el = el;\n this.groupTreeitem = group;\n this.label = el.textContent?.trim() ?? '';\n this.tree = treeObj;\n this.depth = (group?.depth || 0) + 1;\n this.index = 0;\n\n const parent = el.parentElement;\n if (parent?.tagName.toLowerCase() === 'li') {\n parent?.setAttribute('role', 'none');\n }\n el.setAttribute('aria-level', this.depth + '');\n if (el.getAttribute('aria-label')) {\n this.label = el?.getAttribute('aria-label')?.trim() ?? '';\n }\n\n this.isExpandable = false;\n this.isVisible = false;\n this.isInGroup = !!group;\n\n let curr = el.nextElementSibling;\n while (curr) {\n if (curr.tagName.toLowerCase() == 'ul') {\n const groupId = `${group?.label ?? ''} nav group ${this.label}`.replace(/[\\W_]+/g, '_');\n el.setAttribute('aria-owns', groupId);\n el.setAttribute('aria-expanded', 'false');\n curr.setAttribute('role', 'group');\n curr.setAttribute('id', groupId);\n this.isExpandable = true;\n break;\n }\n\n curr = curr.nextElementSibling;\n }\n this.init();\n }\n\n private init() {\n this.el.tabIndex = -1;\n if (!this.el.getAttribute('role')) {\n this.el.setAttribute('role', 'treeitem');\n }\n this.el.addEventListener('keydown', this.handleKeydown.bind(this));\n this.el.addEventListener('click', this.handleClick.bind(this));\n this.el.addEventListener('focus', this.handleFocus.bind(this));\n this.el.addEventListener('blur', this.handleBlur.bind(this));\n }\n\n isExpanded() {\n if (this.isExpandable) {\n return this.el.getAttribute('aria-expanded') === 'true';\n }\n\n return false;\n }\n\n isSelected() {\n return this.el.getAttribute('aria-selected') === 'true';\n }\n\n private handleClick(event: MouseEvent) {\n // only process click events that directly happened on this treeitem\n if (event.target !== this.el && event.target !== this.el.firstElementChild) {\n return;\n }\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n }\n\n private handleFocus() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.add('focus');\n }\n\n private handleBlur() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.remove('focus');\n }\n\n private handleKeydown(event: KeyboardEvent) {\n if (event.altKey || event.ctrlKey || event.metaKey) {\n return;\n }\n\n let captured = false;\n switch (event.key) {\n case ' ':\n case 'Enter':\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n captured = true;\n } else {\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n break;\n\n case 'ArrowUp':\n this.tree.setFocusToPreviousItem(this);\n captured = true;\n break;\n\n case 'ArrowDown':\n this.tree.setFocusToNextItem(this);\n captured = true;\n break;\n\n case 'ArrowRight':\n if (this.isExpandable) {\n if (this.isExpanded()) {\n this.tree.setFocusToNextItem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n }\n captured = true;\n break;\n\n case 'ArrowLeft':\n if (this.isExpandable && this.isExpanded()) {\n this.tree.collapseTreeitem(this);\n captured = true;\n } else {\n if (this.isInGroup) {\n this.tree.setFocusToParentItem(this);\n captured = true;\n }\n }\n break;\n\n case 'Home':\n this.tree.setFocusToFirstItem();\n captured = true;\n break;\n\n case 'End':\n this.tree.setFocusToLastItem();\n captured = true;\n break;\n\n default:\n if (event.key.length === 1 && event.key.match(/\\S/)) {\n if (event.key == '*') {\n this.tree.expandAllSiblingItems(this);\n } else {\n this.tree.setFocusByFirstCharacter(this, event.key);\n }\n captured = true;\n }\n break;\n }\n\n if (captured) {\n event.stopPropagation();\n event.preventDefault();\n }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction debounce any>(func: T, wait: number) {\n let timeout: ReturnType | null;\n return (...args: Parameters) => {\n const later = () => {\n timeout = null;\n func(...args);\n };\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(later, wait);\n };\n}\n", "/*!\n * @license\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * Controller for a table element with expandable rows. Adds event listeners to\n * a toggle within a table row that controls visiblity of additional related\n * rows in the table.\n *\n * @example\n * ```typescript\n * import {ExpandableRowsTableController} from '/static/js/table';\n *\n * const el = document .querySelector('.js-myTableElement')\n * new ExpandableRowsTableController(el));\n * ```\n */\nexport class ExpandableRowsTableController {\n private rows: HTMLTableRowElement[];\n private toggles: HTMLButtonElement[];\n\n /**\n * Create a table controller.\n * @param table - The table element to which the controller binds.\n */\n constructor(private table: HTMLTableElement, private toggleAll?: HTMLButtonElement | null) {\n this.rows = Array.from(table.querySelectorAll('[data-aria-controls]'));\n this.toggles = Array.from(this.table.querySelectorAll('[aria-expanded]'));\n this.setAttributes();\n this.attachEventListeners();\n this.update();\n }\n\n /**\n * setAttributes sets data-aria-* and data-id attributes to regular\n * html attributes as a workaround for limitations from safehtml.\n */\n private setAttributes() {\n for (const a of ['data-aria-controls', 'data-aria-labelledby', 'data-id']) {\n this.table.querySelectorAll(`[${a}]`).forEach(t => {\n t.setAttribute(a.replace('data-', ''), t.getAttribute(a) ?? '');\n t.removeAttribute(a);\n });\n }\n }\n\n private attachEventListeners() {\n this.rows.forEach(t => {\n t.addEventListener('click', e => {\n this.handleToggleClick(e);\n });\n });\n this.toggleAll?.addEventListener('click', () => {\n this.expandAllItems();\n });\n\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n this.expandAllItems();\n }\n });\n }\n\n private handleToggleClick(e: MouseEvent) {\n let target = e.currentTarget as HTMLTableRowElement | null;\n if (!target?.hasAttribute('aria-expanded')) {\n target = this.table.querySelector(\n `button[aria-controls=\"${target?.getAttribute('aria-controls')}\"]`\n );\n }\n const isExpanded = target?.getAttribute('aria-expanded') === 'true';\n target?.setAttribute('aria-expanded', isExpanded ? 'false' : 'true');\n e.stopPropagation();\n this.update();\n }\n\n expandAllItems = (): void => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'true'));\n this.update();\n };\n\n private collapseAllItems = () => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'false'));\n this.update();\n };\n\n private update = () => {\n this.updateVisibleItems();\n setTimeout(() => this.updateGlobalToggle());\n };\n\n private updateVisibleItems() {\n this.rows.map(t => {\n const isExpanded = t?.getAttribute('aria-expanded') === 'true';\n const rowIds = t?.getAttribute('aria-controls')?.trimEnd().split(' ');\n rowIds?.map(id => {\n const target = document.getElementById(`${id}`);\n if (isExpanded) {\n target?.classList.add('visible');\n target?.classList.remove('hidden');\n } else {\n target?.classList.add('hidden');\n target?.classList.remove('visible');\n }\n });\n });\n }\n\n private updateGlobalToggle() {\n if (!this.toggleAll) return;\n if (this.rows.some(t => t.hasAttribute('aria-expanded'))) {\n this.toggleAll.style.display = 'block';\n }\n const someCollapsed = this.toggles.some(el => el.getAttribute('aria-expanded') === 'false');\n if (someCollapsed) {\n this.toggleAll.innerText = 'Expand all';\n this.toggleAll.onclick = this.expandAllItems;\n this.toggleAll.setAttribute('aria-label', 'Expand all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n } else {\n this.toggleAll.innerText = 'Collapse all';\n this.toggleAll.onclick = this.collapseAllItems;\n this.toggleAll.setAttribute('aria-label', 'Collapse all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n }\n }\n}\n", "import { initPlaygrounds } from 'static/shared/playground/playground';\nimport { SelectNavController, makeSelectNav } from 'static/shared/outline/select';\nimport { TreeNavController } from 'static/shared/outline/tree';\nimport { ExpandableRowsTableController } from 'static/shared/table/table';\n\ninitPlaygrounds();\n\nconst directories = document.querySelector('.js-expandableTable');\nif (directories) {\n const table = new ExpandableRowsTableController(\n directories,\n document.querySelector('.js-expandAllDirectories')\n );\n // Expand directories on page load with expand-directories query param.\n if (window.location.search.includes('expand-directories')) {\n table.expandAllItems();\n }\n\n const internalToggle = document.querySelector('.js-showInternalDirectories');\n if (internalToggle) {\n if (document.querySelector('.UnitDirectories-internal')) {\n internalToggle.style.display = 'block';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n }\n internalToggle.addEventListener('click', () => {\n if (directories.classList.contains('UnitDirectories-showInternal')) {\n directories.classList.remove('UnitDirectories-showInternal');\n internalToggle.innerText = 'Show internal';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n } else {\n directories.classList.add('UnitDirectories-showInternal');\n internalToggle.innerText = 'Hide internal';\n internalToggle.setAttribute('aria-label', 'Hide Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'hideInternal-description');\n }\n });\n }\n if (document.querySelector('html[data-local=\"true\"]')) {\n internalToggle?.click();\n }\n}\n\nconst treeEl = document.querySelector('.js-tree');\nif (treeEl) {\n const treeCtrl = new TreeNavController(treeEl);\n const select = makeSelectNav(treeCtrl);\n const mobileNav = document.querySelector('.js-mainNavMobile');\n if (mobileNav && mobileNav.firstElementChild) {\n mobileNav?.replaceChild(select, mobileNav.firstElementChild);\n }\n if (select.firstElementChild) {\n new SelectNavController(select.firstElementChild);\n }\n}\n\n/**\n * Event handlers for expanding and collapsing the readme section.\n */\nconst readme = document.querySelector('.js-readme');\nconst readmeContent = document.querySelector('.js-readmeContent');\nconst readmeOutline = document.querySelector('.js-readmeOutline');\nconst readmeExpand = document.querySelectorAll('.js-readmeExpand');\nconst readmeCollapse = document.querySelector('.js-readmeCollapse');\nconst mobileNavSelect = document.querySelector('.DocNavMobile-select');\nif (readme && readmeContent && readmeOutline && readmeExpand.length && readmeCollapse) {\n if (readme.clientHeight > 320) {\n readme?.classList.remove('UnitReadme--expanded');\n readme?.classList.add('UnitReadme--toggle');\n }\n if (window.location.hash.includes('readme')) {\n expandReadme();\n }\n mobileNavSelect?.addEventListener('change', e => {\n if ((e.target as HTMLSelectElement).value.startsWith('readme-')) {\n expandReadme();\n }\n });\n readmeExpand.forEach(el =>\n el.addEventListener('click', e => {\n e.preventDefault();\n expandReadme();\n readme.scrollIntoView();\n })\n );\n readmeCollapse.addEventListener('click', e => {\n e.preventDefault();\n readme.classList.remove('UnitReadme--expanded');\n if (readmeExpand[1]) {\n readmeExpand[1].scrollIntoView({ block: 'center' });\n }\n });\n readmeContent.addEventListener('keyup', () => {\n expandReadme();\n });\n readmeContent.addEventListener('click', () => {\n expandReadme();\n });\n readmeOutline.addEventListener('click', () => {\n expandReadme();\n });\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n expandReadme();\n }\n });\n}\n\n/**\n * expandReadme expands the readme and adds the section-readme hash to the\n * URL so it stays expanded when navigating back from an external link.\n */\nfunction expandReadme() {\n history.replaceState(null, '', `${location.pathname}${location.search}#section-readme`);\n readme?.classList.add('UnitReadme--expanded');\n}\n\n/**\n * Expand details items that are focused. This will expand\n * deprecated symbols when they are navigated to from the index\n * or a direct link.\n */\nfunction openDeprecatedSymbol() {\n if (!location.hash) return;\n const heading = document.getElementById(location.hash.slice(1));\n const grandParent = heading?.parentElement?.parentElement as HTMLDetailsElement | null;\n if (grandParent?.nodeName === 'DETAILS') {\n grandParent.open = true;\n }\n}\nopenDeprecatedSymbol();\nwindow.addEventListener('hashchange', () => openDeprecatedSymbol());\n\n/**\n * Listen for changes in the build context dropdown.\n */\ndocument.querySelectorAll('.js-buildContextSelect').forEach(el => {\n el.addEventListener('change', e => {\n window.location.search = `?GOOS=${(e.target as HTMLSelectElement).value}`;\n });\n});\n\n/**\n * fork\uFF1Aunexported\uFF08\u79C1\u6709\uFF09\u7B26\u53F7 toggle\u3002\n *\n * \u80CC\u666F\uFF1Apkgsite -show-unexported flag \u8BA9 godoc \u628A\u79C1\u6709 type/func/method\n * \u90FD\u6E32\u5230 page\u3002\u4F46\u8BFB\u8005\u5927\u591A\u6570\u65F6\u5019\u53EA\u5173\u5FC3 public API\uFF0C\u79C1\u6709\u7684\u592A\u591A\u53CD\u800C\u62D6\u6162\n * \u9605\u8BFB\u3002\u8FD9\u5C42\u5728 client \u7AEF\u6309 id \u9996\u5B57\u6BCD\u5927\u5C0F\u5199\u81EA\u52A8 hide \u79C1\u6709 declaration +\n * index \u94FE\u63A5\uFF0C\u518D\u6CE8\u5165\u4E00\u4E2A toggle button \u4E00\u952E\u5207\u663E\u793A\u3002\u72B6\u6001\u7528 localStorage\n * \u8BB0\u4E0B\uFF0C\u8DE8\u9875\u4FDD\u7559\u3002\n */\n(() => {\n if (!document.querySelector('h4[data-kind]')) return; // \u975E godoc \u8BE6\u60C5\u9875\n\n // method id \u5F62\u5982 \"Type.method\"\uFF0C\u53D6\u6700\u540E\u6BB5\u5224\u79C1\u6709\uFF1B\u5176\u4ED6\u76F4\u63A5\u5224 id \u672C\u8EAB\u3002\n // \u6392\u9664 pkg-overview / section-readme / pkg-index \u8FD9\u7C7B\u9875\u9762 anchor\u2014\u2014\u5B83\u4EEC\u662F\n // \u5C0F\u5199\u8D77\u5934\u4F46\u4E0D\u662F Go \u7B26\u53F7\uFF0C\u626B\u5230\u4F1A\u8BEF\u6807\u9690\u85CF\u3002\n const isUnexported = (id: string): boolean => {\n if (id.startsWith('pkg-') || id.startsWith('section-') || id.startsWith('hdr-')) {\n return false;\n }\n const last = id.split('.').pop() ?? id;\n return /^[a-z]/.test(last);\n };\n\n // \u6807 declaration wrapper\uFF1Afunc \u5305\u5728 .Documentation-function\uFF1Btype / method\n // \u5305\u5728 .Documentation-type / .Documentation-typeFunc / .Documentation-typeMethod\u3002\n document.querySelectorAll('h4[data-kind][id]').forEach(h => {\n if (!isUnexported(h.id)) return;\n const wrapper = h.closest(\n '.Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod'\n );\n wrapper?.classList.add('Documentation-unexported');\n });\n\n // index \u5217\u8868\u9879 + \u5DE6\u4FA7\u8FB9\u680F\uFF08go-Tree outline\uFF09\u6309\u94FE\u63A5\u9996\u5B57\u6BCD\u5224\u3002\n // \u4FA7\u8FB9\u680F\u94FE\u63A5 selector \u76F4\u63A5\u5339\u914D\u6240\u6709 .go-Tree a[href^=\"#\"]\u2014\u2014pkg-overview /\n // section-readme \u7B49\u5BFC\u822A anchor \u5DF2\u88AB isUnexported \u5934\u90E8\u6392\u9664\uFF0C\u4E0D\u4F1A\u8BEF\u6807\u3002\n document\n .querySelectorAll(\n '.Documentation-indexFunction a[href^=\"#\"], ' +\n '.Documentation-indexType a[href^=\"#\"], ' +\n '.Documentation-indexTypeFunctions a[href^=\"#\"], ' +\n '.Documentation-indexTypeMethods a[href^=\"#\"], ' +\n '.go-Tree a[href^=\"#\"]'\n )\n .forEach(a => {\n if (isUnexported(a.getAttribute('href')!.slice(1))) {\n a.closest('li')?.classList.add('Documentation-unexported');\n }\n });\n\n // \u6CE8\u5165 CSS\uFF08\u4E0D\u52A8 main.css build pipeline\uFF0C\u907F\u514D\u589E\u91CF\u6539 esbuild \u8F93\u51FA\uFF09\n const style = document.createElement('style');\n style.textContent =\n 'body:not(.show-unexported) .Documentation-unexported{display:none}';\n document.head.appendChild(style);\n\n // \u6CE8\u5165 toggle button\u2014\u2014\u653E Index \u6807\u9898\u65C1\u8FB9\u6700\u663E\u773C\uFF0C\u8DDF \"Show internal\" \u540C\u4F4D\n const indexHeader = document.querySelector('#pkg-index');\n if (!indexHeader) return;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'go-Button go-Button--inline';\n btn.style.marginLeft = '0.75rem';\n btn.style.fontSize = '0.875rem';\n btn.style.verticalAlign = 'middle';\n\n const STORE_KEY = 'gogodocs:showUnexported';\n const apply = (show: boolean) => {\n document.body.classList.toggle('show-unexported', show);\n btn.textContent = show ? 'Hide unexported' : 'Show unexported';\n try {\n localStorage.setItem(STORE_KEY, show ? '1' : '0');\n } catch {\n /* localStorage \u4E0D\u53EF\u7528\uFF08\u9690\u79C1\u6A21\u5F0F / \u6587\u4EF6\u534F\u8BAE\uFF09\u65F6\u5FFD\u7565\uFF0C\u53EA\u4E22\u5931\u8DE8\u9875\u8BB0\u5FC6 */\n }\n };\n\n apply(localStorage.getItem(STORE_KEY) === '1');\n btn.addEventListener('click', () =>\n apply(!document.body.classList.contains('show-unexported'))\n );\n indexHeader.appendChild(btn);\n})();\n"],
+ "mappings": "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",
"names": ["getBasePath", "_a", "abs", "p", "PlayExampleClassName", "PlaygroundExampleController", "exampleEl", "_a", "_b", "_c", "_d", "e", "el", "numLineBreaks", "output", "err", "codeWithModFile", "moduleVars", "PLAYGROUND_BASE_URL", "abs", "res", "shareId", "href", "body", "Body", "Error", "Events", "Errors", "resolve", "initPlaygrounds", "exampleHashRegex", "exampleHashEl", "exampleHrefs", "findExampleHash", "playContainer", "ex", "exampleHref", "SelectNavController", "el", "e", "target", "href", "makeSelectNav", "tree", "label", "select", "outline", "groupMap", "group", "t", "o", "_a", "hash", "value", "TreeNavController", "el", "treeitem", "targets", "observer", "entries", "entry", "id", "isIntersecting", "active", "t", "_a", "fn", "href", "target", "delay", "debounce", "currentItem", "nextItem", "ti", "prevItem", "l1", "groupTreeitem", "char", "start", "index", "findItems", "group", "curr", "TreeItem", "idx", "parent", "focusEl", "startIndex", "treeObj", "_b", "_c", "_d", "_e", "groupId", "event", "captured", "func", "wait", "timeout", "args", "later", "ExpandableRowsTableController", "table", "toggleAll", "t", "a", "_a", "e", "target", "isExpanded", "rowIds", "id", "el", "initPlaygrounds", "directories", "table", "ExpandableRowsTableController", "internalToggle", "treeEl", "treeCtrl", "TreeNavController", "select", "makeSelectNav", "mobileNav", "SelectNavController", "readme", "readmeContent", "readmeOutline", "readmeExpand", "readmeCollapse", "mobileNavSelect", "expandReadme", "e", "el", "openDeprecatedSymbol", "_a", "heading", "grandParent", "isUnexported", "id", "last", "h", "wrapper", "a", "style", "indexHeader", "btn", "STORE_KEY", "apply", "show"]
}
diff --git a/static/frontend/unit/main/main.ts b/static/frontend/unit/main/main.ts
index 64ab596b3..1c612d45e 100644
--- a/static/frontend/unit/main/main.ts
+++ b/static/frontend/unit/main/main.ts
@@ -156,7 +156,12 @@ document.querySelectorAll('.js-buildContextSelect').forEach(el => {
if (!document.querySelector('h4[data-kind]')) return; // 非 godoc 详情页
// method id 形如 "Type.method",取最后段判私有;其他直接判 id 本身。
+ // 排除 pkg-overview / section-readme / pkg-index 这类页面 anchor——它们是
+ // 小写起头但不是 Go 符号,扫到会误标隐藏。
const isUnexported = (id: string): boolean => {
+ if (id.startsWith('pkg-') || id.startsWith('section-') || id.startsWith('hdr-')) {
+ return false;
+ }
const last = id.split('.').pop() ?? id;
return /^[a-z]/.test(last);
};
@@ -171,13 +176,16 @@ document.querySelectorAll('.js-buildContextSelect').forEach(el => {
wrapper?.classList.add('Documentation-unexported');
});
- // index 列表项也按链接首字母判
+ // index 列表项 + 左侧边栏(go-Tree outline)按链接首字母判。
+ // 侧边栏链接 selector 直接匹配所有 .go-Tree a[href^="#"]——pkg-overview /
+ // section-readme 等导航 anchor 已被 isUnexported 头部排除,不会误标。
document
.querySelectorAll(
'.Documentation-indexFunction a[href^="#"], ' +
'.Documentation-indexType a[href^="#"], ' +
'.Documentation-indexTypeFunctions a[href^="#"], ' +
- '.Documentation-indexTypeMethods a[href^="#"]'
+ '.Documentation-indexTypeMethods a[href^="#"], ' +
+ '.go-Tree a[href^="#"]'
)
.forEach(a => {
if (isUnexported(a.getAttribute('href')!.slice(1))) {
From 70d1af98b78d8ccde503c36f474091396aa4794c Mon Sep 17 00:00:00 2001
From: Yechi Yang <95576172+NickWilde18@users.noreply.github.com>
Date: Thu, 7 May 2026 21:19:23 +0800
Subject: [PATCH 11/26] =?UTF-8?q?fix(test):=20patch=20LoadTemplates=20?=
=?UTF-8?q?=E7=AD=BE=E5=90=8D=E6=BC=8F=E7=BD=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
P1 改 dochtml.LoadTemplates 签名加 basePath 时只补了 dochtml 包内
test(dochtml_test.go / symbol_test.go),漏了:
- internal/godoc/render_test.go 30 / 94
- internal/fetch/fetch_test.go 43
加空 basePath 第二个参数。
注:跑 fork 全 test 套件还有一个失败:TestFetchModule/master_version_of_
stdlib_module/stdlibzip 期望 commit hash 89fb59e2e920 实际 2b6a2e56778f。
切回 pristine upstream/master 复现同样 fail——stdlib zip 内容随 Go 版本
变化但 fixture 写死,是上游历史问题,跟 fork patch 无关。
---
internal/fetch/fetch_test.go | 2 +-
internal/godoc/render_test.go | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/internal/fetch/fetch_test.go b/internal/fetch/fetch_test.go
index 5bc060188..3f02aa8dc 100644
--- a/internal/fetch/fetch_test.go
+++ b/internal/fetch/fetch_test.go
@@ -40,7 +40,7 @@ var (
type fetchFunc func(t *testing.T, withLicenseDetector bool, ctx context.Context, mod *proxytest.Module, fetchVersion string) (*FetchResult, *licenses.Detector)
func TestMain(m *testing.M) {
- dochtml.LoadTemplates(templateFS)
+ dochtml.LoadTemplates(templateFS, "")
testModules = proxytest.LoadTestModules("../proxy/testdata")
licenses.OmitExceptions = true
os.Exit(m.Run())
diff --git a/internal/godoc/render_test.go b/internal/godoc/render_test.go
index 75deb3387..33743e276 100644
--- a/internal/godoc/render_test.go
+++ b/internal/godoc/render_test.go
@@ -27,7 +27,7 @@ var (
)
func TestDocInfo(t *testing.T) {
- dochtml.LoadTemplates(templateFS)
+ dochtml.LoadTemplates(templateFS, "")
ctx := context.Background()
si := source.NewGitHubInfo("a.com/M", "", "abcde")
mi := &ModuleInfo{
@@ -91,7 +91,7 @@ func TestDocInfo(t *testing.T) {
}
func TestRenderParts_SinceVersion(t *testing.T) {
- dochtml.LoadTemplates(templateFS)
+ dochtml.LoadTemplates(templateFS, "")
ctx := context.Background()
si := source.NewGitHubInfo("a.com/M", "", "abcde")
mi := &ModuleInfo{
From d4f7372bfd0c55241f9873ab52330dcdc6f9e49d Mon Sep 17 00:00:00 2001
From: Yechi Yang <95576172+NickWilde18@users.noreply.github.com>
Date: Thu, 7 May 2026 21:21:02 +0800
Subject: [PATCH 12/26] =?UTF-8?q?fix(test):=20=E8=A1=A5=E5=85=A8=20LoadTem?=
=?UTF-8?q?plates=20/=20ParsePageTemplates=20=E7=AD=BE=E5=90=8D=E6=BC=8F?=
=?UTF-8?q?=E7=BD=91=EF=BC=88worker=20/=20=E9=9B=86=E6=88=90=E6=B5=8B?=
=?UTF-8?q?=E8=AF=95=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
P1 改这两个函数签名加 basePath 时还有 5 处漏:
- internal/worker/server.go (prod worker 二进制;fork 主走 cmd/pkgsite
但仍要 build 通过)
- internal/worker/server_test.go
- internal/fetchdatasource/fetchdatasource_test.go
- internal/tests/templates/templates_test.go (含 ParsePageTemplates)
- internal/testing/integration/integration_test.go
加空 basePath 第二参数。go vet ./... + go test ./... 全过(除 1 个
TestFetchModule/master_version_of_stdlib_module/stdlibzip——这是上游
fixture 漂移,pristine upstream/master 同样 fail,跟 fork patch 无关)。
golangci-lint 24 issues(errcheck / staticcheck)全是上游历史问题不动。
---
internal/fetchdatasource/fetchdatasource_test.go | 2 +-
internal/testing/integration/integration_test.go | 2 +-
internal/tests/templates/templates_test.go | 4 ++--
internal/worker/server.go | 2 +-
internal/worker/server_test.go | 2 +-
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/internal/fetchdatasource/fetchdatasource_test.go b/internal/fetchdatasource/fetchdatasource_test.go
index 223c38bd9..8cfb2b488 100644
--- a/internal/fetchdatasource/fetchdatasource_test.go
+++ b/internal/fetchdatasource/fetchdatasource_test.go
@@ -35,7 +35,7 @@ var (
)
func TestMain(m *testing.M) {
- dochtml.LoadTemplates(template.TrustedFSFromTrustedSource(template.TrustedSourceFromConstant("../../static")))
+ dochtml.LoadTemplates(template.TrustedFSFromTrustedSource(template.TrustedSourceFromConstant("../../static")), "")
defaultTestModules = proxytest.LoadTestModules("../proxy/testdata")
licenses.OmitExceptions = true
os.Exit(m.Run())
diff --git a/internal/testing/integration/integration_test.go b/internal/testing/integration/integration_test.go
index 6ac8a5ffe..d7c8b1b15 100644
--- a/internal/testing/integration/integration_test.go
+++ b/internal/testing/integration/integration_test.go
@@ -32,7 +32,7 @@ import (
)
func TestMain(m *testing.M) {
- dochtml.LoadTemplates(template.TrustedFSFromTrustedSource(template.TrustedSourceFromConstant("../../../static")))
+ dochtml.LoadTemplates(template.TrustedFSFromTrustedSource(template.TrustedSourceFromConstant("../../../static")), "")
testModules = proxytest.LoadTestModules("../../proxy/testdata")
postgres.RunDBTests("discovery_integration_test", m, &testDB)
}
diff --git a/internal/tests/templates/templates_test.go b/internal/tests/templates/templates_test.go
index 30e43a762..fc2bdde1e 100644
--- a/internal/tests/templates/templates_test.go
+++ b/internal/tests/templates/templates_test.go
@@ -20,7 +20,7 @@ import (
func TestCheckFrontendTemplates(t *testing.T) {
// Perform additional checks on parsed templates.
staticFS := template.TrustedFSFromEmbed(static.FS)
- templates, err := templates.ParsePageTemplates(staticFS)
+ templates, err := templates.ParsePageTemplates(staticFS, "")
if err != nil {
t.Fatal(err)
}
@@ -82,7 +82,7 @@ func TestCheckFrontendTemplates(t *testing.T) {
var templateFS = template.TrustedFSFromTrustedSource(template.TrustedSourceFromConstant("../../../static"))
func TestCheckDocHTMLTemplates(t *testing.T) {
- dochtml.LoadTemplates(templateFS)
+ dochtml.LoadTemplates(templateFS, "")
for _, tm := range dochtml.Templates() {
if err := templatecheck.CheckSafe(tm, dochtml.TemplateData{}); err != nil {
t.Fatal(err)
diff --git a/internal/worker/server.go b/internal/worker/server.go
index eaac081cb..468741312 100644
--- a/internal/worker/server.go
+++ b/internal/worker/server.go
@@ -93,7 +93,7 @@ func NewServer(cfg *config.Config, scfg ServerConfig) (_ *Server, err error) {
}
tfs := template.TrustedFSFromTrustedSource(scfg.StaticPath)
- dochtml.LoadTemplates(tfs)
+ dochtml.LoadTemplates(tfs, "")
var c *cache.Cache
if scfg.RedisCacheClient != nil {
c = cache.New(scfg.RedisCacheClient)
diff --git a/internal/worker/server_test.go b/internal/worker/server_test.go
index 427dce9e6..5072929e8 100644
--- a/internal/worker/server_test.go
+++ b/internal/worker/server_test.go
@@ -37,7 +37,7 @@ var (
func TestMain(m *testing.M) {
httpClient = &http.Client{Transport: fakeTransport{}}
- dochtml.LoadTemplates(template.TrustedFSFromTrustedSource(template.TrustedSourceFromConstant("../../static")))
+ dochtml.LoadTemplates(template.TrustedFSFromTrustedSource(template.TrustedSourceFromConstant("../../static")), "")
testModules = proxytest.LoadTestModules("../proxy/testdata")
postgres.RunDBTests("discovery_worker_test", m, &testDB)
}
From 5c2293551e340329d6d06bdf057327c924148018 Mon Sep 17 00:00:00 2001
From: Yechi Yang <95576172+NickWilde18@users.noreply.github.com>
Date: Thu, 7 May 2026 22:12:19 +0800
Subject: [PATCH 13/26] =?UTF-8?q?chore:=20rename=20gogodocs=20=E2=86=92=20?=
=?UTF-8?q?pkgsitex=20=E5=85=A8=E5=A5=97=E5=BC=95=E7=94=A8=E6=9B=BF?=
=?UTF-8?q?=E6=8D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
GitHub repo 已 rename NickWilde18/gogodocs → NickWilde18/pkgsitex;
本仓库内部 17 个文件里所有 \"gogodocs\" 字面量替换为 \"pkgsitex\",覆盖:
- cmd/pkgsite/main.go:-base-path flag 默认值文案 + comment
- cmd/internal/pkgsite/server.go:ServerConfig.BasePath 注释
- internal/frontend/server.go / versions/versions.go / templates/templates.go
/ fetchserver/fetch.go:godoc 注释里举例 URL 全换
- internal/godoc/render.go / dochtml/dochtml.go / dochtml/template.go:
PackageURL 拼接逻辑注释 + IncludeUnexported 包级 var 注释
- internal/godoc/dochtml/internal/render/markdown_ext.go:注释举例
- static/frontend/unit/main/main.ts:localStorage key
gogodocs:showUnexported → pkgsitex:showUnexported(影响:之前
toggle 状态用户需要重新点一次切换)
- static/frontend/about/index.ts、static/shared/base-path/base-path.ts:
注释里举例 base path
- Dockerfile:org.opencontainers.image.source label
esbuild 已重 build 静态 bundle 同步反映 main.ts / about.ts 改动。
不动 git commit history(之前的 commit message 历史保留 \"gogodocs\"
字面量)。fork 仓库 PR #1 标题 / description 待 update。
Smoke test:本地起 \`-base-path=/pkgsitex\`,主页 + chat.cuhksz module
HTTP 200,渲染 HTML 残留 \"gogodocs\" 引用 0 个。
---
Dockerfile | 2 +-
cmd/internal/pkgsite/server.go | 2 +-
cmd/pkgsite/main.go | 6 +++---
internal/frontend/fetchserver/fetch.go | 2 +-
internal/frontend/server.go | 6 +++---
internal/frontend/templates/templates.go | 6 +++---
internal/frontend/versions/versions.go | 2 +-
internal/godoc/dochtml/dochtml.go | 2 +-
internal/godoc/dochtml/template.go | 4 ++--
internal/godoc/render.go | 2 +-
static/frontend/about/index.js.map | 2 +-
static/frontend/about/index.ts | 2 +-
static/frontend/frontend.js.map | 2 +-
static/frontend/unit/main/main.js | 2 +-
static/frontend/unit/main/main.js.map | 2 +-
static/frontend/unit/main/main.ts | 2 +-
static/shared/base-path/base-path.ts | 8 ++++----
17 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index 8a9282a67..27caf3e7f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -24,7 +24,7 @@ COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /pkgsite ./cmd/pkgsite
FROM golang:1.24
-LABEL org.opencontainers.image.source="https://github.com/NickWilde18/gogodocs"
+LABEL org.opencontainers.image.source="https://github.com/NickWilde18/pkgsitex"
LABEL org.opencontainers.image.description="Self-hosted godoc browser (pkgsite fork) with base-path support"
COPY --from=builder /pkgsite /usr/local/bin/pkgsite
diff --git a/cmd/internal/pkgsite/server.go b/cmd/internal/pkgsite/server.go
index 81e610a76..191e56bf7 100644
--- a/cmd/internal/pkgsite/server.go
+++ b/cmd/internal/pkgsite/server.go
@@ -44,7 +44,7 @@ type ServerConfig struct {
GoDocMode bool
RecordCodeWikiMetrics frontend.RecordClickFunc
- // BasePath:URL 前缀(如 "/gogodocs")让站点挂在子路径下。空 = 挂根。
+ // BasePath:URL 前缀(如 "/pkgsitex")让站点挂在子路径下。空 = 挂根。
// 详见 cmd/pkgsite/main.go 的 -base-path flag。
BasePath string
diff --git a/cmd/pkgsite/main.go b/cmd/pkgsite/main.go
index d24544312..b924b7e40 100644
--- a/cmd/pkgsite/main.go
+++ b/cmd/pkgsite/main.go
@@ -77,10 +77,10 @@ var (
goRepoPath = flag.String("gorepo", "", "path to Go repo on local filesystem")
useProxy = flag.Bool("proxy", false, "fetch from GOPROXY if not found locally")
openFlag = flag.Bool("open", false, "open a browser window to the server's address")
- // basePath:把整个站点挂在 URL 子路径下(如 -base-path=/gogodocs,
- // 站点入口 http://host/gogodocs/)。空字符串 = 默认挂根路径,跟上游一致。
+ // basePath:把整个站点挂在 URL 子路径下(如 -base-path=/pkgsitex,
+ // 站点入口 http://host/pkgsitex/)。空字符串 = 默认挂根路径,跟上游一致。
// fork 加入这个 flag 是为了让 pkgsite 能跟主网关共用域名(反代而非 subdomain)。
- basePath = flag.String("base-path", "", "URL prefix to mount the site under (e.g. /gogodocs). Must start with / and not end with /.")
+ basePath = flag.String("base-path", "", "URL prefix to mount the site under (e.g. /pkgsitex). Must start with / and not end with /.")
// showUnexported:godoc 显示 unexported 符号(doc.AllDecls 模式)。fork
// 内网部署常见诉求——自家代码完整展示比 public-only 视图更有用。
showUnexported = flag.Bool("show-unexported", false, "Render documentation including unexported declarations (doc.AllDecls mode).")
diff --git a/internal/frontend/fetchserver/fetch.go b/internal/frontend/fetchserver/fetch.go
index 46acacbcd..baff89d41 100644
--- a/internal/frontend/fetchserver/fetch.go
+++ b/internal/frontend/fetchserver/fetch.go
@@ -89,7 +89,7 @@ var (
type FetchServer struct {
Queue queue.Queue
TaskIDChangeInterval time.Duration
- // BasePath:站点 URL 子路径前缀(如 "/gogodocs")。空 = 挂根。
+ // BasePath:站点 URL 子路径前缀(如 "/pkgsitex")。空 = 挂根。
// 用于 [ServePathNotFoundPage] 内部 http.Redirect 拼绝对 URL,否则
// /search?q=... 之类的重定向会跳到 reverse proxy 之外。
BasePath string
diff --git a/internal/frontend/server.go b/internal/frontend/server.go
index 59fe187ab..8504ea72f 100644
--- a/internal/frontend/server.go
+++ b/internal/frontend/server.go
@@ -63,7 +63,7 @@ type Server struct {
instanceID string
HTTPClient *http.Client
recordCodeWikiMetrics RecordClickFunc
- // basePath:URL 前缀(如 "/gogodocs"),空字符串 = 默认挂根。
+ // basePath:URL 前缀(如 "/pkgsitex"),空字符串 = 默认挂根。
// 由调用方通过 ServerConfig.BasePath 设置,并贯穿 mux pattern / StripPrefix /
// template "abs" 助手 / 内部 redirect / dochtml 链接拼接,使整站能整体迁移到子路径。
// 关于不变式:basePath 要么空、要么形如 "/foo"——尾部不带斜杠(拼 mux 时双斜杠会失配)。
@@ -106,7 +106,7 @@ type ServerConfig struct {
VulndbClient *vuln.Client
HTTPClient *http.Client
RecordCodeWikiMetrics RecordClickFunc
- // BasePath:URL 子路径前缀(如 "/gogodocs"),空 = 挂根。详见 [Server.basePath]。
+ // BasePath:URL 子路径前缀(如 "/pkgsitex"),空 = 挂根。详见 [Server.basePath]。
BasePath string
}
@@ -193,7 +193,7 @@ type Cacher interface {
// 让 file server 能剥到正确的剩余 path。
func (s *Server) Install(handle func(string, http.Handler), cacher Cacher, authValues []string) {
// shadow 入参 handle:所有 handle("GET /static/", ...) 自动变成
- // realHandle("GET /gogodocs/static/", ...),保持原代码零改动。
+ // realHandle("GET /pkgsitex/static/", ...),保持原代码零改动。
// installDebugHandlers(handle) 透传时也用包装版本——_debug/pprof 等
// 调试端点同样落在 base-path 下。
realHandle := handle
diff --git a/internal/frontend/templates/templates.go b/internal/frontend/templates/templates.go
index a6c190e43..bb1994f9d 100644
--- a/internal/frontend/templates/templates.go
+++ b/internal/frontend/templates/templates.go
@@ -44,8 +44,8 @@ func stripScheme(url string) string {
// funcsWithBasePath 在内置 templateFuncs 之上叠两个 base-path 助手:
//
// - `{{abs "/static/foo.svg"}}` → 静态绝对路径前置 BasePath,
-// 站点挂根时输出 `/static/foo.svg`,挂 -base-path=/gogodocs 时输出
-// `/gogodocs/static/foo.svg`。必须以 / 开头;否则原样(让作者改时一目了然)。
+// 站点挂根时输出 `/static/foo.svg`,挂 -base-path=/pkgsitex 时输出
+// `/pkgsitex/static/foo.svg`。必须以 / 开头;否则原样(让作者改时一目了然)。
// 返回 [safehtml.TrustedResourceURL]——safehtml/template 不会校验,允许
// 模板里跟 `?version={{.AppVersionLabel}}` 等动态 query 拼接(普通
// string return 会被 safehtml 拒绝,认为 ?version= 不是合法 URL prefix)。
@@ -104,7 +104,7 @@ func funcsWithBasePath(basePath string) template.FuncMap {
// ParsePageTemplates parses html templates contained in the given filesystem in
// order to generate a map of Name->*template.Template.
//
-// basePath 形如 "/gogodocs" 或空字符串。空 = 站点挂根(pkg.go.dev 行为)。
+// basePath 形如 "/pkgsitex" 或空字符串。空 = 站点挂根(pkg.go.dev 行为)。
// 模板里通过 `{{abs "/static/foo.svg"}}` 输出带 prefix 的绝对 URL。
//
// Separate templates are used so that certain contextual functions (e.g.
diff --git a/internal/frontend/versions/versions.go b/internal/frontend/versions/versions.go
index 43056e859..80a6077ca 100644
--- a/internal/frontend/versions/versions.go
+++ b/internal/frontend/versions/versions.go
@@ -430,7 +430,7 @@ func absoluteTime(date time.Time) string {
return date.In(time.UTC).Format("Jan _2, 2006")
}
-// BasePath 是 fork 加的包级 URL 前缀(如 "/gogodocs"),由 cmd/pkgsite/main.go
+// BasePath 是 fork 加的包级 URL 前缀(如 "/pkgsitex"),由 cmd/pkgsite/main.go
// 在 -base-path flag 处设置。空 = 默认挂根,跟上游零差异。
//
// [ConstructUnitURL] 是 pkgsite 内部所有 unit / package / module 详情页链接
diff --git a/internal/godoc/dochtml/dochtml.go b/internal/godoc/dochtml/dochtml.go
index 8407e6f4e..d3586ddbb 100644
--- a/internal/godoc/dochtml/dochtml.go
+++ b/internal/godoc/dochtml/dochtml.go
@@ -286,7 +286,7 @@ func renderInfo(ctx context.Context, fset *token.FileSet, p *doc.Package, opt Re
if opt.BuildContext.GOOS != "" && opt.BuildContext.GOOS != "all" {
search = "?GOOS=" + opt.BuildContext.GOOS
}
- // basePath 在站点挂子路径时非空(如 "/gogodocs")——godoc 渲染的
+ // basePath 在站点挂子路径时非空(如 "/pkgsitex")——godoc 渲染的
// cross-reference 链接(如 std lib ``)拼上前缀
// 才能在反代环境正确路由。
return basePath + "/" + versionedPath + search
diff --git a/internal/godoc/dochtml/template.go b/internal/godoc/dochtml/template.go
index 95e869e6d..0eb5bf7af 100644
--- a/internal/godoc/dochtml/template.go
+++ b/internal/godoc/dochtml/template.go
@@ -22,7 +22,7 @@ var (
// then it becomes more viable to factor out inline CSS style.
bodyTemplate, outlineTemplate, sidenavTemplate *template.Template
- // basePath:单进程包级 URL 前缀(如 "/gogodocs"),由 [LoadTemplates] 写入;
+ // basePath:单进程包级 URL 前缀(如 "/pkgsitex"),由 [LoadTemplates] 写入;
// 渲染 godoc cross-reference 时([dochtml.go] 的 PackageURL)拼到链接前。
// dochtml 包是单实例使用,存包级 var 可接受——pkgsite 单进程只有一个 BasePath。
basePath string
@@ -38,7 +38,7 @@ func Templates() []*template.Template {
// LoadTemplates reads and parses the templates used to generate documentation.
//
-// basePathPrefix 形如 "/gogodocs" 或空字符串。空 = 站点挂根(pkg.go.dev 行为)。
+// basePathPrefix 形如 "/pkgsitex" 或空字符串。空 = 站点挂根(pkg.go.dev 行为)。
// 仅在第一次调用生效(loadOnce 之后包级 templates 已 freeze),但 basePath
// 每次调用都会覆盖——单进程 pkgsite 全程只配一个 BasePath,重复写无副作用。
func LoadTemplates(fsys template.TrustedFS, basePathPrefix string) {
diff --git a/internal/godoc/render.go b/internal/godoc/render.go
index c509ab3aa..5c31344ce 100644
--- a/internal/godoc/render.go
+++ b/internal/godoc/render.go
@@ -58,7 +58,7 @@ var IncludeUnexported bool
//
// 用途:cmd/pkgsite local mode 下,[Renderer] 生成 view source / file link 时
// source.Info 走的是 `/files/{path}` 模板,不带 fork 站点子路径。挂
-// -base-path=/gogodocs 时这些链接得变成 `/gogodocs/files/{path}` 才能正确路由
+// -base-path=/pkgsitex 时这些链接得变成 `/pkgsitex/files/{path}` 才能正确路由
// 到 file mux。在 [renderOptions] 的 fileLinkFunc / sourceLinkFunc 里识别 local
// 模式(URL 以 "/files/" 起头)并 prefix。
var BasePath string
diff --git a/static/frontend/about/index.js.map b/static/frontend/about/index.js.map
index 3304fc4ec..005aed200 100644
--- a/static/frontend/about/index.js.map
+++ b/static/frontend/about/index.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../shared/base-path/base-path.ts", "index.ts"],
- "sourcesContent": ["/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/gogodocs \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/gogodocs\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/gogodocs/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/gogodocs/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/**\n * @license\n * Copyright 2022 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { abs } from '../../shared/base-path/base-path';\n\n/**\n * Left Navigation.\n */\nexport const initJumpLinks = async function () {\n // pathname \u5728\u6302 -base-path=/gogodocs \u65F6\u662F \"/gogodocs/about\"\u2014\u2014\u6BD4\u8F83\u5217\u8868\u4E5F\u5F97\u5E26\u524D\u7F00\n const pagesWithJumpLinks = [abs('/about')];\n if (!pagesWithJumpLinks.includes(window.location.pathname)) {\n // stop the file from doing anything else if the page doesn't have jumplinks\n return;\n }\n\n // these might be generated or not so don't grab references to the elements until actually need them.\n const titles = 'h2, h3, h4';\n const nav = '.LeftNav a';\n // these are always in the dom so we can get them now and throw errors if they're not.\n const leftNav = document.querySelector('.LeftNav');\n const siteContent = document.querySelector('.go-Content');\n let isObserverDisabled = false;\n\n /**\n * El function\n * @example el('h1', {className: 'title'}, 'Welcome to the site');\n * @example el('ul', {className: 'list'}, el('li', {}, 'Item one'), el('li', {}, 'Item two'), el('li', {}, 'Item three'));\n * @example el('img', {src: '/url.svg'});\n */\n function el(\n type = '',\n props: { [key: string]: string } = {},\n ...children: (HTMLElement | HTMLElement[] | string | undefined)[]\n ) {\n // Error, no type declared.\n if (!type) {\n throw new Error('Provide `type` to create document element.');\n }\n\n // Create element with optional attribute props\n const docEl = Object.assign(document.createElement(type), props);\n\n // Children: array containing strings or elements\n children.forEach(child => {\n if (typeof child === 'string') {\n docEl.appendChild(document.createTextNode(child));\n } else if (Array.isArray(child)) {\n child.forEach(c => docEl.appendChild(c));\n } else if (child instanceof HTMLElement) {\n docEl.appendChild(child);\n }\n });\n\n return docEl;\n }\n /** Build Nav if data hydrate is present. */\n function buildNav() {\n return new Promise((resolve, reject) => {\n let navItems: { id: string; label: string; subnav?: { id: string; label: string }[] }[] = [];\n let elements: HTMLElement[] = [];\n\n if (!siteContent || !leftNav) {\n return reject('.SiteContent not found.');\n }\n if (leftNav instanceof HTMLElement && !leftNav?.dataset?.hydrate) {\n return resolve(true);\n }\n\n for (const title of siteContent.querySelectorAll(titles)) {\n if (title instanceof HTMLElement && !title?.dataset?.ignore) {\n switch (title.tagName) {\n case 'H2':\n navItems = [\n ...navItems,\n {\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n },\n ];\n break;\n\n case 'H3':\n case 'H4':\n if (!navItems[navItems.length - 1]?.subnav) {\n navItems[navItems.length - 1].subnav = [\n {\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n },\n ];\n } else if (navItems[navItems.length - 1].subnav) {\n navItems[navItems.length - 1].subnav?.push({\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n });\n }\n break;\n }\n }\n }\n\n for (const navItem of navItems) {\n const link = el('a', { href: '#' + navItem.id }, el('span', {}, navItem.label));\n elements = [...elements, link];\n if (navItem?.subnav) {\n let subLinks: HTMLElement[] = [];\n for (const subnavItem of navItem.subnav) {\n const subItem = el(\n 'li',\n {},\n el(\n 'a',\n { href: '#' + subnavItem.id },\n el('img', { src: abs('/static/frontend/about/dot.svg'), width: '5', height: '5' }),\n el('span', {}, subnavItem.label)\n )\n );\n subLinks = [...subLinks, subItem];\n }\n const list = el('ul', { className: 'LeftSubnav' }, subLinks);\n elements = [...elements, list];\n }\n }\n\n elements.forEach(element => leftNav.appendChild(element));\n\n return resolve(true);\n });\n }\n /**\n * Set the correct active element.\n */\n function setNav() {\n return new Promise(resolve => {\n if (!document.querySelectorAll(nav)) return resolve(true);\n for (const a of document.querySelectorAll(nav)) {\n if (a instanceof HTMLAnchorElement && a.href === location.href) {\n setElementActive(a);\n break;\n }\n }\n resolve(true);\n });\n }\n /** resetNav: removes all .active from nav elements */\n function resetNav() {\n return new Promise(resolve => {\n if (!document.querySelectorAll(nav)) return resolve(true);\n for (const a of document.querySelectorAll(nav)) {\n a.classList.remove('active');\n }\n resolve(true);\n });\n }\n /** setElementActive: controls resetting nav and highlighting the appropriate nav items */\n function setElementActive(element: HTMLAnchorElement) {\n if (element instanceof HTMLAnchorElement) {\n resetNav().then(() => {\n element.classList.add('active');\n const parent = element?.parentNode?.parentNode;\n if (parent instanceof HTMLElement && parent?.classList?.contains('LeftSubnav')) {\n parent.previousElementSibling?.classList.add('active');\n }\n });\n }\n }\n /** setLinkManually: disables observer and selects the clicked nav item. */\n function setLinkManually() {\n delayObserver();\n const link = document.querySelector('[href=\"' + location.hash + '\"]');\n if (link instanceof HTMLAnchorElement) {\n setElementActive(link);\n }\n }\n /** delayObserver: Quick on off switch for intersection observer. */\n function delayObserver() {\n isObserverDisabled = true;\n setTimeout(() => {\n isObserverDisabled = false;\n }, 200);\n }\n /** observeSections: kicks off observation of titles as well as manual clicks with hashchange */\n function observeSections() {\n window.addEventListener('hashchange', setLinkManually);\n\n if (siteContent?.querySelectorAll(titles)) {\n const callback: IntersectionObserverCallback = entries => {\n if (!isObserverDisabled && Array.isArray(entries) && entries.length > 0) {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target instanceof HTMLElement) {\n const { id } = entry.target;\n const link = document.querySelector('[href=\"#' + id + '\"]');\n if (link instanceof HTMLAnchorElement) {\n setElementActive(link);\n }\n break;\n }\n }\n }\n };\n // rootMargin is important when multiple sections are in the observable area **on page load**.\n // they will still be highlighted on scroll because of the root margin.\n const ob = new IntersectionObserver(callback, {\n threshold: 0,\n rootMargin: '0px 0px -50% 0px',\n });\n for (const title of siteContent.querySelectorAll(titles)) {\n if (title instanceof HTMLElement && !title?.dataset?.ignore) {\n ob.observe(title);\n }\n }\n }\n }\n\n try {\n await buildNav();\n await setNav();\n if (location.hash) {\n delayObserver();\n }\n observeSections();\n } catch (e) {\n if (e instanceof Error) {\n console.error(e.message);\n } else {\n console.error(e);\n }\n }\n};\n"],
+ "sourcesContent": ["/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/pkgsitex \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/pkgsitex\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/pkgsitex/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/pkgsitex/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/**\n * @license\n * Copyright 2022 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { abs } from '../../shared/base-path/base-path';\n\n/**\n * Left Navigation.\n */\nexport const initJumpLinks = async function () {\n // pathname \u5728\u6302 -base-path=/pkgsitex \u65F6\u662F \"/pkgsitex/about\"\u2014\u2014\u6BD4\u8F83\u5217\u8868\u4E5F\u5F97\u5E26\u524D\u7F00\n const pagesWithJumpLinks = [abs('/about')];\n if (!pagesWithJumpLinks.includes(window.location.pathname)) {\n // stop the file from doing anything else if the page doesn't have jumplinks\n return;\n }\n\n // these might be generated or not so don't grab references to the elements until actually need them.\n const titles = 'h2, h3, h4';\n const nav = '.LeftNav a';\n // these are always in the dom so we can get them now and throw errors if they're not.\n const leftNav = document.querySelector('.LeftNav');\n const siteContent = document.querySelector('.go-Content');\n let isObserverDisabled = false;\n\n /**\n * El function\n * @example el('h1', {className: 'title'}, 'Welcome to the site');\n * @example el('ul', {className: 'list'}, el('li', {}, 'Item one'), el('li', {}, 'Item two'), el('li', {}, 'Item three'));\n * @example el('img', {src: '/url.svg'});\n */\n function el(\n type = '',\n props: { [key: string]: string } = {},\n ...children: (HTMLElement | HTMLElement[] | string | undefined)[]\n ) {\n // Error, no type declared.\n if (!type) {\n throw new Error('Provide `type` to create document element.');\n }\n\n // Create element with optional attribute props\n const docEl = Object.assign(document.createElement(type), props);\n\n // Children: array containing strings or elements\n children.forEach(child => {\n if (typeof child === 'string') {\n docEl.appendChild(document.createTextNode(child));\n } else if (Array.isArray(child)) {\n child.forEach(c => docEl.appendChild(c));\n } else if (child instanceof HTMLElement) {\n docEl.appendChild(child);\n }\n });\n\n return docEl;\n }\n /** Build Nav if data hydrate is present. */\n function buildNav() {\n return new Promise((resolve, reject) => {\n let navItems: { id: string; label: string; subnav?: { id: string; label: string }[] }[] = [];\n let elements: HTMLElement[] = [];\n\n if (!siteContent || !leftNav) {\n return reject('.SiteContent not found.');\n }\n if (leftNav instanceof HTMLElement && !leftNav?.dataset?.hydrate) {\n return resolve(true);\n }\n\n for (const title of siteContent.querySelectorAll(titles)) {\n if (title instanceof HTMLElement && !title?.dataset?.ignore) {\n switch (title.tagName) {\n case 'H2':\n navItems = [\n ...navItems,\n {\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n },\n ];\n break;\n\n case 'H3':\n case 'H4':\n if (!navItems[navItems.length - 1]?.subnav) {\n navItems[navItems.length - 1].subnav = [\n {\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n },\n ];\n } else if (navItems[navItems.length - 1].subnav) {\n navItems[navItems.length - 1].subnav?.push({\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n });\n }\n break;\n }\n }\n }\n\n for (const navItem of navItems) {\n const link = el('a', { href: '#' + navItem.id }, el('span', {}, navItem.label));\n elements = [...elements, link];\n if (navItem?.subnav) {\n let subLinks: HTMLElement[] = [];\n for (const subnavItem of navItem.subnav) {\n const subItem = el(\n 'li',\n {},\n el(\n 'a',\n { href: '#' + subnavItem.id },\n el('img', { src: abs('/static/frontend/about/dot.svg'), width: '5', height: '5' }),\n el('span', {}, subnavItem.label)\n )\n );\n subLinks = [...subLinks, subItem];\n }\n const list = el('ul', { className: 'LeftSubnav' }, subLinks);\n elements = [...elements, list];\n }\n }\n\n elements.forEach(element => leftNav.appendChild(element));\n\n return resolve(true);\n });\n }\n /**\n * Set the correct active element.\n */\n function setNav() {\n return new Promise(resolve => {\n if (!document.querySelectorAll(nav)) return resolve(true);\n for (const a of document.querySelectorAll(nav)) {\n if (a instanceof HTMLAnchorElement && a.href === location.href) {\n setElementActive(a);\n break;\n }\n }\n resolve(true);\n });\n }\n /** resetNav: removes all .active from nav elements */\n function resetNav() {\n return new Promise(resolve => {\n if (!document.querySelectorAll(nav)) return resolve(true);\n for (const a of document.querySelectorAll(nav)) {\n a.classList.remove('active');\n }\n resolve(true);\n });\n }\n /** setElementActive: controls resetting nav and highlighting the appropriate nav items */\n function setElementActive(element: HTMLAnchorElement) {\n if (element instanceof HTMLAnchorElement) {\n resetNav().then(() => {\n element.classList.add('active');\n const parent = element?.parentNode?.parentNode;\n if (parent instanceof HTMLElement && parent?.classList?.contains('LeftSubnav')) {\n parent.previousElementSibling?.classList.add('active');\n }\n });\n }\n }\n /** setLinkManually: disables observer and selects the clicked nav item. */\n function setLinkManually() {\n delayObserver();\n const link = document.querySelector('[href=\"' + location.hash + '\"]');\n if (link instanceof HTMLAnchorElement) {\n setElementActive(link);\n }\n }\n /** delayObserver: Quick on off switch for intersection observer. */\n function delayObserver() {\n isObserverDisabled = true;\n setTimeout(() => {\n isObserverDisabled = false;\n }, 200);\n }\n /** observeSections: kicks off observation of titles as well as manual clicks with hashchange */\n function observeSections() {\n window.addEventListener('hashchange', setLinkManually);\n\n if (siteContent?.querySelectorAll(titles)) {\n const callback: IntersectionObserverCallback = entries => {\n if (!isObserverDisabled && Array.isArray(entries) && entries.length > 0) {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target instanceof HTMLElement) {\n const { id } = entry.target;\n const link = document.querySelector('[href=\"#' + id + '\"]');\n if (link instanceof HTMLAnchorElement) {\n setElementActive(link);\n }\n break;\n }\n }\n }\n };\n // rootMargin is important when multiple sections are in the observable area **on page load**.\n // they will still be highlighted on scroll because of the root margin.\n const ob = new IntersectionObserver(callback, {\n threshold: 0,\n rootMargin: '0px 0px -50% 0px',\n });\n for (const title of siteContent.querySelectorAll(titles)) {\n if (title instanceof HTMLElement && !title?.dataset?.ignore) {\n ob.observe(title);\n }\n }\n }\n }\n\n try {\n await buildNav();\n await setNav();\n if (location.hash) {\n delayObserver();\n }\n observeSections();\n } catch (e) {\n if (e instanceof Error) {\n console.error(e.message);\n } else {\n console.error(e);\n }\n }\n};\n"],
"mappings": "AAeO,SAASA,GAAsB,CAftC,IAAAC,EAgBE,OAAOA,EAAA,SAAS,gBAAgB,QAAQ,WAAjC,KAAAA,EAA6C,EACtD,CAaO,SAASC,EAAIC,EAAmB,CACrC,OAAKA,EAAE,WAAW,GAAG,EACdH,EAAY,EAAIG,EADQA,CAEjC,CCrBO,IAAMC,EAAgB,gBAAkB,CAG7C,GAAI,CADuB,CAACC,EAAI,QAAQ,CAAC,EACjB,SAAS,OAAO,SAAS,QAAQ,EAEvD,OAIF,IAAMC,EAAS,aACTC,EAAM,aAENC,EAAU,SAAS,cAAc,UAAU,EAC3CC,EAAc,SAAS,cAAc,aAAa,EACpDC,EAAqB,GAQzB,SAASC,EACPC,EAAO,GACPC,EAAmC,CAAC,KACjCC,EACH,CAEA,GAAI,CAACF,EACH,MAAM,IAAI,MAAM,4CAA4C,EAI9D,IAAMG,EAAQ,OAAO,OAAO,SAAS,cAAcH,CAAI,EAAGC,CAAK,EAG/D,OAAAC,EAAS,QAAQE,GAAS,CACpB,OAAOA,GAAU,SACnBD,EAAM,YAAY,SAAS,eAAeC,CAAK,CAAC,EACvC,MAAM,QAAQA,CAAK,EAC5BA,EAAM,QAAQC,GAAKF,EAAM,YAAYE,CAAC,CAAC,EAC9BD,aAAiB,aAC1BD,EAAM,YAAYC,CAAK,CAE3B,CAAC,EAEMD,CACT,CAEA,SAASG,GAAW,CAClB,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CA9D5C,IAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EA+DM,IAAIC,EAAsF,CAAC,EACvFC,EAA0B,CAAC,EAE/B,GAAI,CAACvB,GAAe,CAACD,EACnB,OAAOY,EAAO,yBAAyB,EAEzC,GAAIZ,aAAmB,aAAe,GAACa,EAAAb,GAAA,YAAAA,EAAS,UAAT,MAAAa,EAAkB,SACvD,OAAOF,EAAQ,EAAI,EAGrB,QAAWc,KAASxB,EAAY,iBAAiBH,CAAM,EACrD,GAAI2B,aAAiB,aAAe,GAACX,EAAAW,GAAA,YAAAA,EAAO,UAAP,MAAAX,EAAgB,QACnD,OAAQW,EAAM,QAAS,CACrB,IAAK,KACHF,EAAW,CACT,GAAGA,EACH,CACE,GAAIE,EAAM,GACV,OAAOV,EAAAU,GAAA,YAAAA,EAAO,UAAP,MAAAV,EAAgB,MAAQU,EAAM,QAAQ,OAAQT,EAAAS,EAAM,cAAN,KAAAT,EAAqB,EAC5E,CACF,EACA,MAEF,IAAK,KACL,IAAK,MACEC,EAAAM,EAASA,EAAS,OAAS,CAAC,IAA5B,MAAAN,EAA+B,OAOzBM,EAASA,EAAS,OAAS,CAAC,EAAE,UACvCD,EAAAC,EAASA,EAAS,OAAS,CAAC,EAAE,SAA9B,MAAAD,EAAsC,KAAK,CACzC,GAAIG,EAAM,GACV,OAAOL,EAAAK,GAAA,YAAAA,EAAO,UAAP,MAAAL,EAAgB,MAAQK,EAAM,QAAQ,OAAQJ,EAAAI,EAAM,cAAN,KAAAJ,EAAqB,EAC5E,IAVAE,EAASA,EAAS,OAAS,CAAC,EAAE,OAAS,CACrC,CACE,GAAIE,EAAM,GACV,OAAOP,EAAAO,GAAA,YAAAA,EAAO,UAAP,MAAAP,EAAgB,MAAQO,EAAM,QAAQ,OAAQN,EAAAM,EAAM,cAAN,KAAAN,EAAqB,EAC5E,CACF,EAOF,KACJ,CAIJ,QAAWO,KAAWH,EAAU,CAC9B,IAAMI,EAAOxB,EAAG,IAAK,CAAE,KAAM,IAAMuB,EAAQ,EAAG,EAAGvB,EAAG,OAAQ,CAAC,EAAGuB,EAAQ,KAAK,CAAC,EAE9E,GADAF,EAAW,CAAC,GAAGA,EAAUG,CAAI,EACzBD,GAAA,MAAAA,EAAS,OAAQ,CACnB,IAAIE,EAA0B,CAAC,EAC/B,QAAWC,KAAcH,EAAQ,OAAQ,CACvC,IAAMI,EAAU3B,EACd,KACA,CAAC,EACDA,EACE,IACA,CAAE,KAAM,IAAM0B,EAAW,EAAG,EAC5B1B,EAAG,MAAO,CAAE,IAAKN,EAAI,gCAAgC,EAAG,MAAO,IAAK,OAAQ,GAAI,CAAC,EACjFM,EAAG,OAAQ,CAAC,EAAG0B,EAAW,KAAK,CACjC,CACF,EACAD,EAAW,CAAC,GAAGA,EAAUE,CAAO,EAElC,IAAMC,EAAO5B,EAAG,KAAM,CAAE,UAAW,YAAa,EAAGyB,CAAQ,EAC3DJ,EAAW,CAAC,GAAGA,EAAUO,CAAI,GAIjC,OAAAP,EAAS,QAAQQ,GAAWhC,EAAQ,YAAYgC,CAAO,CAAC,EAEjDrB,EAAQ,EAAI,CACrB,CAAC,CACH,CAIA,SAASsB,GAAS,CAChB,OAAO,IAAI,QAAQtB,GAAW,CAC5B,GAAI,CAAC,SAAS,iBAAiBZ,CAAG,EAAG,OAAOY,EAAQ,EAAI,EACxD,QAAWuB,KAAK,SAAS,iBAAiBnC,CAAG,EAC3C,GAAImC,aAAa,mBAAqBA,EAAE,OAAS,SAAS,KAAM,CAC9DC,EAAiBD,CAAC,EAClB,MAGJvB,EAAQ,EAAI,CACd,CAAC,CACH,CAEA,SAASyB,GAAW,CAClB,OAAO,IAAI,QAAQzB,GAAW,CAC5B,GAAI,CAAC,SAAS,iBAAiBZ,CAAG,EAAG,OAAOY,EAAQ,EAAI,EACxD,QAAWuB,KAAK,SAAS,iBAAiBnC,CAAG,EAC3CmC,EAAE,UAAU,OAAO,QAAQ,EAE7BvB,EAAQ,EAAI,CACd,CAAC,CACH,CAEA,SAASwB,EAAiBH,EAA4B,CAChDA,aAAmB,mBACrBI,EAAS,EAAE,KAAK,IAAM,CAlK5B,IAAAvB,EAAAC,EAAAC,EAmKQiB,EAAQ,UAAU,IAAI,QAAQ,EAC9B,IAAMK,GAASxB,EAAAmB,GAAA,YAAAA,EAAS,aAAT,YAAAnB,EAAqB,WAChCwB,aAAkB,eAAevB,EAAAuB,GAAA,YAAAA,EAAQ,YAAR,MAAAvB,EAAmB,SAAS,kBAC/DC,EAAAsB,EAAO,yBAAP,MAAAtB,EAA+B,UAAU,IAAI,UAEjD,CAAC,CAEL,CAEA,SAASuB,GAAkB,CACzBC,EAAc,EACd,IAAMZ,EAAO,SAAS,cAAc,UAAY,SAAS,KAAO,IAAI,EAChEA,aAAgB,mBAClBQ,EAAiBR,CAAI,CAEzB,CAEA,SAASY,GAAgB,CACvBrC,EAAqB,GACrB,WAAW,IAAM,CACfA,EAAqB,EACvB,EAAG,GAAG,CACR,CAEA,SAASsC,GAAkB,CA3L7B,IAAA3B,EA8LI,GAFA,OAAO,iBAAiB,aAAcyB,CAAe,EAEjDrC,GAAA,MAAAA,EAAa,iBAAiBH,GAAS,CACzC,IAAM2C,EAAyCC,GAAW,CACxD,GAAI,CAACxC,GAAsB,MAAM,QAAQwC,CAAO,GAAKA,EAAQ,OAAS,GACpE,QAAWC,KAASD,EAClB,GAAIC,EAAM,gBAAkBA,EAAM,kBAAkB,YAAa,CAC/D,GAAM,CAAE,GAAAC,CAAG,EAAID,EAAM,OACfhB,EAAO,SAAS,cAAc,WAAaiB,EAAK,IAAI,EACtDjB,aAAgB,mBAClBQ,EAAiBR,CAAI,EAEvB,OAIR,EAGMkB,EAAK,IAAI,qBAAqBJ,EAAU,CAC5C,UAAW,EACX,WAAY,kBACd,CAAC,EACD,QAAWhB,KAASxB,EAAY,iBAAiBH,CAAM,EACjD2B,aAAiB,aAAe,GAACZ,EAAAY,GAAA,YAAAA,EAAO,UAAP,MAAAZ,EAAgB,SACnDgC,EAAG,QAAQpB,CAAK,EAIxB,CAEA,GAAI,CACF,MAAMf,EAAS,EACf,MAAMuB,EAAO,EACT,SAAS,MACXM,EAAc,EAEhBC,EAAgB,CAClB,OAASM,EAAP,CACIA,aAAa,MACf,QAAQ,MAAMA,EAAE,OAAO,EAEvB,QAAQ,MAAMA,CAAC,CAEnB,CACF",
"names": ["getBasePath", "_a", "abs", "p", "initJumpLinks", "abs", "titles", "nav", "leftNav", "siteContent", "isObserverDisabled", "el", "type", "props", "children", "docEl", "child", "c", "buildNav", "resolve", "reject", "_a", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "navItems", "elements", "title", "navItem", "link", "subLinks", "subnavItem", "subItem", "list", "element", "setNav", "a", "setElementActive", "resetNav", "parent", "setLinkManually", "delayObserver", "observeSections", "callback", "entries", "entry", "id", "ob", "e"]
}
diff --git a/static/frontend/about/index.ts b/static/frontend/about/index.ts
index 6f2ea53a3..0e08d1605 100644
--- a/static/frontend/about/index.ts
+++ b/static/frontend/about/index.ts
@@ -11,7 +11,7 @@ import { abs } from '../../shared/base-path/base-path';
* Left Navigation.
*/
export const initJumpLinks = async function () {
- // pathname 在挂 -base-path=/gogodocs 时是 "/gogodocs/about"——比较列表也得带前缀
+ // pathname 在挂 -base-path=/pkgsitex 时是 "/pkgsitex/about"——比较列表也得带前缀
const pagesWithJumpLinks = [abs('/about')];
if (!pagesWithJumpLinks.includes(window.location.pathname)) {
// stop the file from doing anything else if the page doesn't have jumplinks
diff --git a/static/frontend/frontend.js.map b/static/frontend/frontend.js.map
index dca67f047..0b262a0fd 100644
--- a/static/frontend/frontend.js.map
+++ b/static/frontend/frontend.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../shared/header/header.ts", "../shared/base-path/base-path.ts", "../shared/carousel/carousel.ts", "../shared/clipboard/clipboard.ts", "../shared/tooltip/tooltip.ts", "../shared/outline/select.ts", "../shared/modal/modal.ts", "../shared/analytics/analytics.ts", "../shared/keyboard/keyboard.ts", "../shared/jump/jump.ts", "about/index.ts", "frontend.ts"],
- "sourcesContent": ["/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nexport function registerHeaderListeners(): void {\n const header = document.querySelector('.js-header') as HTMLElement;\n\n // Desktop menu hover state\n const menuItemHovers = document.querySelectorAll('.js-desktop-menu-hover');\n menuItemHovers.forEach(menuItemHover => {\n // when user clicks on the dropdown menu item on desktop or mobile,\n // force the menu to stay open until the user clicks off of it.\n menuItemHover.addEventListener('mouseenter', e => {\n const target = e.target as HTMLElement;\n const forced = document.querySelector('.forced-open') as HTMLElement;\n if (forced && forced !== menuItemHover) {\n forced.blur();\n forced.classList.remove('forced-open');\n }\n // prevents menus that have been tabbed into from staying open\n // when you hover over another menu\n target.classList.remove('forced-closed');\n target.classList.add('forced-open');\n });\n\n const toggleForcedOpen = (e: Event) => {\n const target = e.target as HTMLElement;\n const isForced = target?.classList.contains('forced-open');\n const currentTarget = e.currentTarget as HTMLElement;\n if (isForced) {\n currentTarget.removeEventListener('blur', () =>\n currentTarget.classList.remove('forced-open')\n );\n currentTarget.classList.remove('forced-open');\n currentTarget.classList.add('forced-closed');\n currentTarget.blur();\n currentTarget?.parentNode?.addEventListener('mouseout', () => {\n currentTarget.classList.remove('forced-closed');\n });\n } else {\n currentTarget.classList.remove('forced-closed');\n currentTarget.classList.add('forced-open');\n currentTarget.focus();\n currentTarget.addEventListener('blur', () => currentTarget.classList.remove('forced-open'));\n currentTarget?.parentNode?.removeEventListener('mouseout', () => {\n currentTarget.classList.remove('forced-closed');\n });\n }\n currentTarget.focus();\n };\n menuItemHover.addEventListener('click', toggleForcedOpen);\n menuItemHover.addEventListener('focus', e => {\n const target = e.target as HTMLElement;\n target.classList.add('forced-closed');\n target.classList.remove('forced-open');\n });\n\n // ensure desktop submenus are closed when esc is pressed\n const closeSubmenuOnEsc = (e: Event) => {\n const event = e as KeyboardEvent;\n const target = e.target as HTMLElement;\n if (event.key === 'Escape') {\n const forcedOpenItem = document.querySelector('.forced-open') as HTMLElement;\n if (forcedOpenItem) {\n forcedOpenItem.classList.remove('forced-open');\n forcedOpenItem.blur();\n forcedOpenItem.classList.add('forced-closed');\n target?.focus();\n }\n }\n };\n document.addEventListener('keydown', closeSubmenuOnEsc);\n });\n\n // Mobile menu subnav menus\n const headerbuttons = document.querySelectorAll('.js-headerMenuButton');\n headerbuttons.forEach(button => {\n button.addEventListener('click', e => {\n e.preventDefault();\n const isActive = header?.classList.contains('is-active');\n if (isActive) {\n handleNavigationDrawerInactive(header);\n } else {\n handleNavigationDrawerActive(header);\n }\n button.setAttribute('aria-expanded', isActive ? 'true' : 'false');\n });\n });\n\n const scrim = document.querySelector('.js-scrim');\n scrim?.addEventListener('click', e => {\n e.preventDefault();\n\n // find any active submenus and close them\n const activeSubnavs = document.querySelectorAll('.go-NavigationDrawer-submenuItem.is-active');\n activeSubnavs.forEach(subnav => handleNavigationDrawerInactive(subnav as HTMLElement));\n\n handleNavigationDrawerInactive(header);\n\n headerbuttons.forEach(button => {\n button.setAttribute(\n 'aria-expanded',\n header?.classList.contains('is-active') ? 'true' : 'false'\n );\n });\n });\n\n const getNavigationDrawerMenuItems = (navigationDrawer: HTMLElement): HTMLElement[] => {\n if (!navigationDrawer) {\n return [];\n }\n\n const menuItems = Array.from(\n navigationDrawer.querySelectorAll(\n ':scope > .go-NavigationDrawer-nav > .go-NavigationDrawer-list > .go-NavigationDrawer-listItem > a, :scope > .go-NavigationDrawer-nav > .go-NavigationDrawer-list > .go-NavigationDrawer-listItem > .go-Header-socialIcons > a'\n ) || []\n );\n\n const anchorEl = navigationDrawer.querySelector('.go-NavigationDrawer-header > a');\n if (anchorEl) {\n menuItems.unshift(anchorEl);\n }\n return menuItems as HTMLElement[];\n };\n\n const getNavigationDrawerIsSubnav = (navigationDrawer: HTMLElement) => {\n if (!navigationDrawer) {\n return;\n }\n return navigationDrawer.classList.contains('go-NavigationDrawer-submenuItem');\n };\n\n const handleNavigationDrawerInactive = (navigationDrawer: HTMLElement) => {\n if (!navigationDrawer) {\n return;\n }\n const menuItems = getNavigationDrawerMenuItems(navigationDrawer);\n navigationDrawer.classList.remove('is-active');\n const parentMenuItem = navigationDrawer\n .closest('.go-NavigationDrawer-listItem')\n ?.querySelector(':scope > a') as HTMLElement;\n parentMenuItem?.focus();\n menuItems?.forEach(item => item?.setAttribute('tabindex', '-1'));\n if (menuItems && menuItems[0]) {\n menuItems[0].removeEventListener('keydown', handleMenuItemTabLeftFactory(navigationDrawer));\n menuItems[menuItems.length - 1].removeEventListener(\n 'keydown',\n handleMenuItemTabRightFactory(navigationDrawer)\n );\n }\n\n if (navigationDrawer === header) {\n headerbuttons && (headerbuttons[0] as HTMLElement)?.focus();\n }\n };\n\n const handleNavigationDrawerActive = (navigationDrawer: HTMLElement) => {\n const menuItems = getNavigationDrawerMenuItems(navigationDrawer);\n\n navigationDrawer.classList.add('is-active');\n menuItems.forEach(item => item.setAttribute('tabindex', '0'));\n menuItems[0].focus();\n\n menuItems[0].addEventListener('keydown', handleMenuItemTabLeftFactory(navigationDrawer));\n menuItems[menuItems.length - 1].addEventListener(\n 'keydown',\n handleMenuItemTabRightFactory(navigationDrawer)\n );\n };\n\n const handleMenuItemTabLeftFactory = (navigationDrawer: HTMLElement) => {\n return (e: KeyboardEvent) => {\n if (e.key === 'Tab' && e.shiftKey) {\n e.preventDefault();\n handleNavigationDrawerInactive(navigationDrawer);\n }\n };\n };\n\n const handleMenuItemTabRightFactory = (navigationDrawer: HTMLElement) => {\n return (e: KeyboardEvent) => {\n if (e.key === 'Tab' && !e.shiftKey) {\n e.preventDefault();\n handleNavigationDrawerInactive(navigationDrawer);\n }\n };\n };\n\n const prepMobileNavigationDrawer = (navigationDrawer: HTMLElement) => {\n const isSubnav = getNavigationDrawerIsSubnav(navigationDrawer);\n const menuItems = getNavigationDrawerMenuItems(navigationDrawer);\n navigationDrawer.addEventListener('keyup', e => {\n if (e.key === 'Escape') {\n handleNavigationDrawerInactive(navigationDrawer);\n }\n });\n\n menuItems.forEach(item => {\n const parentLi = item.closest('li');\n if (parentLi && parentLi.classList.contains('js-mobile-subnav-trigger')) {\n const submenu = parentLi.querySelector('.go-NavigationDrawer-submenuItem') as HTMLElement;\n item.addEventListener('click', () => {\n handleNavigationDrawerActive(submenu);\n });\n }\n });\n if (isSubnav) {\n handleNavigationDrawerInactive(navigationDrawer);\n navigationDrawer\n ?.querySelector('.go-NavigationDrawer-header')\n ?.addEventListener('click', e => {\n e.preventDefault();\n handleNavigationDrawerInactive(navigationDrawer);\n });\n }\n };\n\n document\n .querySelectorAll('.go-NavigationDrawer')\n .forEach(drawer => prepMobileNavigationDrawer(drawer as HTMLElement));\n\n handleNavigationDrawerInactive(header);\n}\n\nexport function registerSearchFormListeners(): void {\n const searchForm = document.querySelector('.js-searchForm');\n const expandSearch = document.querySelector('.js-expandSearch');\n const input = searchForm?.querySelector('input');\n const headerLogo = document.querySelector('.js-headerLogo');\n const menuButton = document.querySelector('.js-headerMenuButton');\n expandSearch?.addEventListener('click', () => {\n searchForm?.classList.add('go-SearchForm--expanded');\n headerLogo?.classList.add('go-Header-logo--hidden');\n menuButton?.classList.add('go-Header-navOpen--hidden');\n input?.focus();\n });\n document?.addEventListener('click', e => {\n if (!searchForm?.contains(e.target as Node)) {\n searchForm?.classList.remove('go-SearchForm--expanded');\n headerLogo?.classList.remove('go-Header-logo--hidden');\n menuButton?.classList.remove('go-Header-navOpen--hidden');\n }\n });\n}\n", "/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/gogodocs \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/gogodocs\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/gogodocs/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/gogodocs/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { getBasePath } from '../base-path/base-path';\n\n/**\n * Carousel Controller adds event listeners, accessibility enhancements, and\n * control elements to a carousel component.\n */\nexport class CarouselController {\n /**\n * slides is a collection of slides in the carousel.\n */\n private slides: HTMLLIElement[];\n /**\n * dots is a collection of dot navigation controls, added to the carousel\n * by this controller.\n */\n private dots: HTMLElement[];\n /**\n * liveRegion is a visually hidden element that notifies assitive devices\n * of visual changes to the carousel. They are added to the carousel by\n * this controller.\n */\n private liveRegion: HTMLElement;\n /**\n * activeIndex is the 0-index of the currently active slide.\n */\n private activeIndex: number;\n\n constructor(private el: HTMLElement) {\n this.slides = Array.from(el.querySelectorAll('.go-Carousel-slide'));\n this.dots = [];\n this.liveRegion = document.createElement('div');\n this.activeIndex = Number(el.getAttribute('data-slide-index') ?? 0);\n\n this.initSlides();\n this.initArrows();\n this.initDots();\n this.initLiveRegion();\n }\n\n private initSlides() {\n for (const [i, v] of this.slides.entries()) {\n if (i === this.activeIndex) continue;\n v.setAttribute('aria-hidden', 'true');\n }\n }\n\n private initArrows() {\n const arrows = document.createElement('ul');\n arrows.classList.add('go-Carousel-arrows');\n // base path \u901A\u8FC7 [getBasePath]() \u6CE8\u5165\uFF1B\u6302\u6839\u65F6\u8FD4\u7A7A\u5B57\u7B26\u4E32\uFF0C\u5BF9\u4E0A\u6E38\u96F6\u5DEE\u5F02\u3002\n const bp = getBasePath();\n arrows.innerHTML = `\n \n \n \n \n \n \n \n \n \n \n `;\n arrows\n .querySelector('.go-Carousel-prevSlide')\n ?.addEventListener('click', () => this.setActive(this.activeIndex - 1));\n arrows\n .querySelector('.go-Carousel-nextSlide')\n ?.addEventListener('click', () => this.setActive(this.activeIndex + 1));\n this.el.append(arrows);\n }\n\n private initDots() {\n const dots = document.createElement('ul');\n dots.classList.add('go-Carousel-dots');\n for (let i = 0; i < this.slides.length; i++) {\n const li = document.createElement('li');\n const button = document.createElement('button');\n button.classList.add('go-Carousel-dot');\n if (i === this.activeIndex) {\n button.classList.add('go-Carousel-dot--active');\n }\n button.innerHTML = `Slide ${i + 1} `;\n button.addEventListener('click', () => this.setActive(i));\n li.append(button);\n dots.append(li);\n this.dots.push(button);\n }\n this.el.append(dots);\n }\n\n private initLiveRegion() {\n this.liveRegion.setAttribute('aria-live', 'polite');\n this.liveRegion.setAttribute('aria-atomic', 'true');\n this.liveRegion.setAttribute('class', 'go-Carousel-obscured');\n this.liveRegion.textContent = `Slide ${this.activeIndex + 1} of ${this.slides.length}`;\n this.el.appendChild(this.liveRegion);\n }\n\n private setActive = (index: number) => {\n this.activeIndex = (index + this.slides.length) % this.slides.length;\n this.el.setAttribute('data-slide-index', String(this.activeIndex));\n for (const d of this.dots) {\n d.classList.remove('go-Carousel-dot--active');\n }\n this.dots[this.activeIndex].classList.add('go-Carousel-dot--active');\n for (const s of this.slides) {\n s.setAttribute('aria-hidden', 'true');\n }\n this.slides[this.activeIndex].removeAttribute('aria-hidden');\n this.liveRegion.textContent = 'Slide ' + (this.activeIndex + 1) + ' of ' + this.slides.length;\n };\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * This class decorates an element to copy arbitrary data attached via a data-\n * attribute to the clipboard.\n */\nexport class ClipboardController {\n /**\n * The data to be copied to the clipboard.\n */\n private data: string;\n\n /**\n * @param el The element that will trigger copying text to the clipboard. The text is\n * expected to be within its data-to-copy attribute.\n */\n constructor(private el: HTMLButtonElement) {\n this.data = el.dataset['toCopy'] ?? el.innerText;\n // if data-to-copy is empty and the button is part of an input group\n // capture the value of the input.\n if (!this.data && el.parentElement?.classList.contains('go-InputGroup')) {\n this.data = (this.data || el.parentElement?.querySelector('input')?.value) ?? '';\n }\n el.addEventListener('click', e => this.handleCopyClick(e));\n }\n\n /**\n * Handles when the primary element is clicked.\n */\n handleCopyClick(e: MouseEvent): void {\n e.preventDefault();\n const TOOLTIP_SHOW_DURATION_MS = 1000;\n\n // This API is not available on iOS.\n if (!navigator.clipboard) {\n this.showTooltipText('Unable to copy', TOOLTIP_SHOW_DURATION_MS);\n return;\n }\n navigator.clipboard\n .writeText(this.data)\n .then(() => {\n this.showTooltipText('Copied!', TOOLTIP_SHOW_DURATION_MS);\n })\n .catch(() => {\n this.showTooltipText('Unable to copy', TOOLTIP_SHOW_DURATION_MS);\n });\n }\n\n /**\n * Shows the given text in a tooltip for a specified amount of time, in milliseconds.\n */\n showTooltipText(text: string, durationMs: number): void {\n this.el.setAttribute('data-tooltip', text);\n setTimeout(() => this.el.setAttribute('data-tooltip', ''), durationMs);\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * ToolTipController handles closing tooltips on external clicks.\n */\nexport class ToolTipController {\n constructor(private el: HTMLDetailsElement) {\n document.addEventListener('click', e => {\n const insideTooltip = this.el.contains(e.target as Element);\n if (!insideTooltip) {\n this.el.removeAttribute('open');\n }\n });\n\n // Add event listener for \"Escape\" keydown to close tooltip\n this.el.addEventListener('keydown', e => {\n if (e.key === 'Escape') {\n this.el.open = false;\n }\n });\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { TreeNavController } from './tree.js';\n\nexport class SelectNavController {\n constructor(private el: Element) {\n this.el.addEventListener('change', e => {\n const target = e.target as HTMLSelectElement;\n let href = target.value;\n if (!target.value.startsWith('/')) {\n href = '/' + href;\n }\n window.location.href = href;\n });\n }\n}\n\nexport function makeSelectNav(tree: TreeNavController): HTMLLabelElement {\n const label = document.createElement('label');\n label.classList.add('go-Label');\n label.setAttribute('aria-label', 'Menu');\n const select = document.createElement('select');\n select.classList.add('go-Select', 'js-selectNav');\n label.appendChild(select);\n const outline = document.createElement('optgroup');\n outline.label = 'Outline';\n select.appendChild(outline);\n const groupMap: Record = {};\n let group: HTMLOptGroupElement;\n for (const t of tree.treeitems) {\n if (Number(t.depth) > 4) continue;\n if (t.groupTreeitem) {\n group = groupMap[t.groupTreeitem.label];\n if (!group) {\n group = groupMap[t.groupTreeitem.label] = document.createElement('optgroup');\n group.label = t.groupTreeitem.label;\n select.appendChild(group);\n }\n } else {\n group = outline;\n }\n const o = document.createElement('option');\n o.label = t.label;\n o.textContent = t.label;\n o.value = (t.el as HTMLAnchorElement).href.replace(window.location.origin, '').replace('/', '');\n group.appendChild(o);\n }\n tree.addObserver(t => {\n const hash = (t.el as HTMLAnchorElement).hash;\n const value = select.querySelector(`[value$=\"${hash}\"]`)?.value;\n if (value) {\n select.value = value;\n }\n }, 50);\n return label;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\ninterface Window {\n dialogPolyfill?: {\n registerDialog: (el: HTMLDialogElement) => void;\n };\n}\n\ndeclare const window: Window;\n\n/**\n * ModalController registers a dialog element with the polyfill if\n * necessary for the current browser, add adds event listeners to\n * close and open modals.\n */\nexport class ModalController {\n constructor(private el: HTMLDialogElement) {\n if (window.dialogPolyfill) {\n window.dialogPolyfill.registerDialog(el);\n }\n this.init();\n }\n\n init() {\n const button = document.querySelector(`[aria-controls=\"${this.el.id}\"]`);\n if (button) {\n button.addEventListener('click', () => {\n if (this.el.showModal) {\n this.el.showModal();\n } else {\n this.el.setAttribute('opened', 'true');\n }\n this.el.querySelector('input')?.focus();\n });\n }\n for (const btn of this.el.querySelectorAll('[data-modal-close]')) {\n btn.addEventListener('click', () => {\n if (this.el.close) {\n this.el.close();\n } else {\n this.el.removeAttribute('opened');\n }\n });\n }\n }\n}\n", "interface TagManagerEvent {\n /**\n * event is the name of the event, used to filter events in\n * Google Analytics.\n */\n event: string;\n\n /**\n * event_category is a name that you supply as a way to group objects\n * that to analyze. Typically, you will use the same category name\n * multiple times over related UI elements (buttons, links, etc).\n */\n event_category?: string;\n\n /**\n * event_action is used to name the type of event or interaction you\n * want to measure for a particular web object. For example, with a\n * single \"form\" category, you can analyze a number of specific events\n * with this parameter, such as: form entered, form submitted.\n */\n event_action?: string;\n\n /**\n * event_label provide additional information for events that you want\n * to analyze, such as the text label of a link.\n */\n event_label?: string;\n\n /**\n * gtm.start is used to initialize Google Tag Manager.\n */\n 'gtm.start'?: number;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\ndeclare global {\n interface Window {\n dataLayer?: (TagManagerEvent | VoidFunction)[];\n ga?: unknown;\n }\n}\n\n/**\n * track sends events to Google Tag Manager.\n */\nexport function track(\n event: string | TagManagerEvent,\n category?: string,\n action?: string,\n label?: string\n): void {\n window.dataLayer ??= [];\n if (typeof event === 'string') {\n window.dataLayer.push({\n event,\n event_category: category,\n event_action: action,\n event_label: label,\n });\n } else {\n window.dataLayer.push(event);\n }\n}\n\n/**\n * func adds functions to run sequentionally after\n * Google Tag Manager is ready.\n */\nexport function func(fn: () => void): void {\n window.dataLayer ??= [];\n window.dataLayer.push(fn);\n}\n", "/*!\n * @license\n * Copyright 2019-2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { track } from '../analytics/analytics';\n\n/**\n * Options are keyhandler callback options.\n */\ninterface Options {\n /**\n * target is the element the key event should filter on. The\n * default target is the document.\n */\n target?: Element;\n\n /**\n * withMeta specifies if the event callback should fire when\n * the key is pressed with a meta key (ctrl, alt, etc). By\n * default meta keypresses are ignored.\n */\n withMeta?: boolean;\n}\n\n/**\n * KeyHandler is the config for a keyboard event callback.\n */\ninterface KeyHandler extends Options {\n description: string;\n callback: (e: KeyboardEvent) => void;\n}\n\n/**\n * KeyboardController controls event callbacks for sitewide\n * keyboard events. Multiple callbacks can be registered for\n * a single key and by default the controller ignores events\n * for text input targets.\n */\nclass KeyboardController {\n handlers: Record>;\n\n constructor() {\n this.handlers = {};\n document.addEventListener('keydown', e => this.handleKeyPress(e));\n }\n\n /**\n * on registers keyboard event callbacks.\n * @param key the key to register.\n * @param description name of the event.\n * @param callback event callback.\n * @param options set target and withMeta options to override the default behaviors.\n */\n on(key: string, description: string, callback: (e: KeyboardEvent) => void, options?: Options) {\n this.handlers[key] ??= new Set();\n this.handlers[key].add({ description, callback, ...options });\n return this;\n }\n\n private handleKeyPress(e: KeyboardEvent) {\n for (const handler of this.handlers[e.key.toLowerCase()] ?? new Set()) {\n if (handler.target && handler.target !== e.target) {\n return;\n }\n const t = e.target as HTMLElement | null;\n if (\n !handler.target &&\n (t?.tagName === 'INPUT' || t?.tagName === 'SELECT' || t?.tagName === 'TEXTAREA')\n ) {\n return;\n }\n if (t?.isContentEditable) {\n return;\n }\n if (\n (handler.withMeta && !(e.ctrlKey || e.metaKey)) ||\n (!handler.withMeta && (e.ctrlKey || e.metaKey))\n ) {\n return;\n }\n track('keypress', 'hotkeys', `${e.key} pressed`, handler.description);\n handler.callback(e);\n }\n }\n}\n\nexport const keyboard = new KeyboardController();\n", "/*!\n * @license\n * Copyright 2019-2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the behavior of the \"jump to symbol\" dialog for Go\n// package documentation, as well as the simple dialog that displays keyboard\n// shortcuts.\n\n// The DOM for the dialogs is at the bottom of static/frontend/unit/main/_modals.tmpl.\n// The CSS is in static/frontend/unit/main/_modals.css.\n\n// The dialog is activated by pressing the 'f' key. It presents a list\n// (#JumpDialog-list) of all Go symbols displayed in the documentation.\n// Entering text in the dialog's text box (#JumpDialog-filter) restricts the\n// list to symbols containing the text. Clicking on an symbol jumps to\n// its documentation.\n\n// This code is based on\n// https://go.googlesource.com/gddo/+/refs/heads/master/gddo-server/assets/site.js.\n// It was modified to remove the dependence on jquery and bootstrap.\n\nimport { keyboard } from '../keyboard/keyboard';\n\nexport function initModals(): void {\n const jumpDialog = document.querySelector('.JumpDialog');\n const jumpBody = jumpDialog?.querySelector('.JumpDialog-body');\n const jumpList = jumpDialog?.querySelector('.JumpDialog-list');\n const jumpFilter = jumpDialog?.querySelector('.JumpDialog-input');\n const doc = document.querySelector('.js-documentation');\n\n interface JumpListItem {\n link: HTMLAnchorElement;\n name: string;\n kind: string;\n lower: string;\n }\n\n let jumpListItems: JumpListItem[] | undefined; // All the symbols in the doc; computed only once.\n\n // collectJumpListItems returns a list of items, one for each symbol in the\n // documentation on the current page.\n //\n // It uses the data-kind attribute generated in the documentation HTML to find\n // the symbols and their id attributes.\n //\n // If there are no data-kind attributes, then we have older doc; fall back to\n // a less precise method.\n function collectJumpListItems() {\n const items = [];\n if (!doc) return;\n for (const el of doc.querySelectorAll('[data-kind]')) {\n items.push(newJumpListItem(el));\n }\n\n // Clicking on any of the links closes the dialog.\n for (const item of items) {\n item.link.addEventListener('click', function () {\n jumpDialog?.close();\n });\n }\n // Sort case-insensitively by symbol name.\n items.sort(function (a, b) {\n return a.lower.localeCompare(b.lower);\n });\n return items;\n }\n\n // newJumpListItem creates a new item for the DOM element el.\n // An item is an object with:\n // - name: the element's id (which is the symbol name)\n // - kind: the element's kind (function, variable, etc.),\n // - link: a link ('a' tag) to the element\n // - lower: the name in lower case, just for sorting\n function newJumpListItem(el: Element): JumpListItem {\n const a = document.createElement('a');\n const name = el.getAttribute('id');\n a.setAttribute('href', '#' + name);\n a.setAttribute('tabindex', '-1');\n a.setAttribute('data-gtmc', 'jump to link');\n const kind = el.getAttribute('data-kind');\n return {\n link: a,\n name: name ?? '',\n kind: kind ?? '',\n lower: name?.toLowerCase() ?? '', // for sorting\n };\n }\n\n let lastFilterValue: string; // The last contents of the filter text box.\n let activeJumpItem = -1; // The index of the currently active item in the list.\n\n // updateJumpList sets the elements of the dialog list to\n // everything whose name contains filter.\n function updateJumpList(filter: string) {\n lastFilterValue = filter;\n if (!jumpListItems) {\n jumpListItems = collectJumpListItems();\n }\n setActiveJumpItem(-1);\n\n // Remove all children from list.\n while (jumpList?.firstChild) {\n jumpList.firstChild.remove();\n }\n\n if (filter) {\n // A filter is set. We treat the filter as a substring that can appear in\n // an item name (case insensitive), and find the following matches - in\n // order of priority:\n //\n // 1. Exact matches (the filter matches the item's name exactly)\n // 2. Prefix matches (the item's name starts with filter)\n // 3. Infix matches (the filter is a substring of the item's name)\n const filterLowerCase = filter.toLowerCase();\n\n const exactMatches = [];\n const prefixMatches = [];\n const infixMatches = [];\n\n // makeLinkHtml creates the link name HTML for a list item. item is the DOM\n // item. item.name.substr(boldStart, boldEnd) will be bolded.\n const makeLinkHtml = (item: JumpListItem, boldStart: number, boldEnd: number) => {\n return (\n item.name.substring(0, boldStart) +\n '' +\n item.name.substring(boldStart, boldEnd) +\n ' ' +\n item.name.substring(boldEnd)\n );\n };\n\n for (const item of jumpListItems ?? []) {\n const nameLowerCase = item.name.toLowerCase();\n\n if (nameLowerCase === filterLowerCase) {\n item.link.innerHTML = makeLinkHtml(item, 0, item.name.length);\n exactMatches.push(item);\n } else if (nameLowerCase.startsWith(filterLowerCase)) {\n item.link.innerHTML = makeLinkHtml(item, 0, filter.length);\n prefixMatches.push(item);\n } else {\n const index = nameLowerCase.indexOf(filterLowerCase);\n if (index > -1) {\n item.link.innerHTML = makeLinkHtml(item, index, index + filter.length);\n infixMatches.push(item);\n }\n }\n }\n\n for (const item of exactMatches.concat(prefixMatches).concat(infixMatches)) {\n jumpList?.appendChild(item.link);\n }\n } else {\n if (!jumpListItems || jumpListItems.length === 0) {\n const msg = document.createElement('i');\n msg.innerHTML = 'There are no symbols on this page.';\n jumpList?.appendChild(msg);\n }\n // No filter set; display all items in their existing order.\n for (const item of jumpListItems ?? []) {\n item.link.innerHTML = item.name + ' ' + item.kind + ' ';\n jumpList?.appendChild(item.link);\n }\n }\n\n if (jumpBody) {\n jumpBody.scrollTop = 0;\n }\n if (jumpListItems?.length && jumpList && jumpList.children.length > 0) {\n setActiveJumpItem(0);\n }\n }\n\n // Set the active jump item to n.\n function setActiveJumpItem(n: number) {\n const cs = jumpList?.children as HTMLCollectionOf | null | undefined;\n if (!cs || !jumpBody) {\n return;\n }\n if (activeJumpItem >= 0) {\n cs[activeJumpItem].classList.remove('JumpDialog-active');\n }\n if (n >= cs.length) {\n n = cs.length - 1;\n }\n if (n >= 0) {\n cs[n].classList.add('JumpDialog-active');\n\n // Scroll so the active item is visible.\n // For some reason cs[n].scrollIntoView() doesn't behave as I'd expect:\n // it moves the entire dialog box in the viewport.\n\n // Get the top and bottom of the active item relative to jumpBody.\n const activeTop = cs[n].offsetTop - cs[0].offsetTop;\n const activeBottom = activeTop + cs[n].clientHeight;\n if (activeTop < jumpBody.scrollTop) {\n // Off the top; scroll up.\n jumpBody.scrollTop = activeTop;\n } else if (activeBottom > jumpBody.scrollTop + jumpBody.clientHeight) {\n // Off the bottom; scroll down.\n jumpBody.scrollTop = activeBottom - jumpBody.clientHeight;\n }\n }\n activeJumpItem = n;\n }\n\n // Increment the activeJumpItem by delta.\n function incActiveJumpItem(delta: number) {\n if (activeJumpItem < 0) {\n return;\n }\n let n = activeJumpItem + delta;\n if (n < 0) {\n n = 0;\n }\n setActiveJumpItem(n);\n }\n\n // Pressing a key in the filter updates the list (if the filter actually changed).\n jumpFilter?.addEventListener('keyup', function () {\n if (jumpFilter.value.toUpperCase() != lastFilterValue.toUpperCase()) {\n updateJumpList(jumpFilter.value);\n }\n });\n\n // Pressing enter in the filter selects the first element in the list.\n jumpFilter?.addEventListener('keydown', function (event) {\n const upArrow = 38;\n const downArrow = 40;\n const enterKey = 13;\n switch (event.which) {\n case upArrow:\n incActiveJumpItem(-1);\n event.preventDefault();\n break;\n case downArrow:\n incActiveJumpItem(1);\n event.preventDefault();\n break;\n case enterKey:\n if (activeJumpItem >= 0) {\n if (jumpList) {\n (jumpList.children[activeJumpItem] as HTMLElement).click();\n event.preventDefault();\n }\n }\n break;\n }\n });\n\n const shortcutsDialog = document.querySelector('.ShortcutsDialog');\n\n // - Pressing 'f' or 'F' opens the jump-to-symbol dialog.\n // - Pressing '?' opens up the shortcut dialog.\n // Ignore a keypress if a dialog is already open, or if it is pressed on a\n // component that wants to consume it.\n keyboard\n .on('f', 'open jump to modal', e => {\n if (jumpDialog?.open || shortcutsDialog?.open) {\n return;\n }\n e.preventDefault();\n if (jumpFilter) {\n jumpFilter.value = '';\n }\n jumpDialog?.showModal?.();\n jumpFilter?.focus();\n updateJumpList('');\n })\n .on('?', 'open shortcuts modal', () => {\n if (jumpDialog?.open || shortcutsDialog?.open) {\n return;\n }\n shortcutsDialog?.showModal?.();\n });\n\n const jumpOutlineInput = document.querySelector('.js-jumpToInput');\n if (jumpOutlineInput) {\n jumpOutlineInput.addEventListener('click', () => {\n if (jumpFilter) {\n jumpFilter.value = '';\n }\n updateJumpList('');\n if (jumpDialog?.open || shortcutsDialog?.open) {\n return;\n }\n jumpDialog?.showModal?.();\n jumpFilter?.focus();\n });\n }\n\n document.querySelector('.js-openShortcuts')?.addEventListener('click', () => {\n shortcutsDialog?.showModal?.();\n });\n}\n", "/**\n * @license\n * Copyright 2022 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { abs } from '../../shared/base-path/base-path';\n\n/**\n * Left Navigation.\n */\nexport const initJumpLinks = async function () {\n // pathname \u5728\u6302 -base-path=/gogodocs \u65F6\u662F \"/gogodocs/about\"\u2014\u2014\u6BD4\u8F83\u5217\u8868\u4E5F\u5F97\u5E26\u524D\u7F00\n const pagesWithJumpLinks = [abs('/about')];\n if (!pagesWithJumpLinks.includes(window.location.pathname)) {\n // stop the file from doing anything else if the page doesn't have jumplinks\n return;\n }\n\n // these might be generated or not so don't grab references to the elements until actually need them.\n const titles = 'h2, h3, h4';\n const nav = '.LeftNav a';\n // these are always in the dom so we can get them now and throw errors if they're not.\n const leftNav = document.querySelector('.LeftNav');\n const siteContent = document.querySelector('.go-Content');\n let isObserverDisabled = false;\n\n /**\n * El function\n * @example el('h1', {className: 'title'}, 'Welcome to the site');\n * @example el('ul', {className: 'list'}, el('li', {}, 'Item one'), el('li', {}, 'Item two'), el('li', {}, 'Item three'));\n * @example el('img', {src: '/url.svg'});\n */\n function el(\n type = '',\n props: { [key: string]: string } = {},\n ...children: (HTMLElement | HTMLElement[] | string | undefined)[]\n ) {\n // Error, no type declared.\n if (!type) {\n throw new Error('Provide `type` to create document element.');\n }\n\n // Create element with optional attribute props\n const docEl = Object.assign(document.createElement(type), props);\n\n // Children: array containing strings or elements\n children.forEach(child => {\n if (typeof child === 'string') {\n docEl.appendChild(document.createTextNode(child));\n } else if (Array.isArray(child)) {\n child.forEach(c => docEl.appendChild(c));\n } else if (child instanceof HTMLElement) {\n docEl.appendChild(child);\n }\n });\n\n return docEl;\n }\n /** Build Nav if data hydrate is present. */\n function buildNav() {\n return new Promise((resolve, reject) => {\n let navItems: { id: string; label: string; subnav?: { id: string; label: string }[] }[] = [];\n let elements: HTMLElement[] = [];\n\n if (!siteContent || !leftNav) {\n return reject('.SiteContent not found.');\n }\n if (leftNav instanceof HTMLElement && !leftNav?.dataset?.hydrate) {\n return resolve(true);\n }\n\n for (const title of siteContent.querySelectorAll(titles)) {\n if (title instanceof HTMLElement && !title?.dataset?.ignore) {\n switch (title.tagName) {\n case 'H2':\n navItems = [\n ...navItems,\n {\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n },\n ];\n break;\n\n case 'H3':\n case 'H4':\n if (!navItems[navItems.length - 1]?.subnav) {\n navItems[navItems.length - 1].subnav = [\n {\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n },\n ];\n } else if (navItems[navItems.length - 1].subnav) {\n navItems[navItems.length - 1].subnav?.push({\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n });\n }\n break;\n }\n }\n }\n\n for (const navItem of navItems) {\n const link = el('a', { href: '#' + navItem.id }, el('span', {}, navItem.label));\n elements = [...elements, link];\n if (navItem?.subnav) {\n let subLinks: HTMLElement[] = [];\n for (const subnavItem of navItem.subnav) {\n const subItem = el(\n 'li',\n {},\n el(\n 'a',\n { href: '#' + subnavItem.id },\n el('img', { src: abs('/static/frontend/about/dot.svg'), width: '5', height: '5' }),\n el('span', {}, subnavItem.label)\n )\n );\n subLinks = [...subLinks, subItem];\n }\n const list = el('ul', { className: 'LeftSubnav' }, subLinks);\n elements = [...elements, list];\n }\n }\n\n elements.forEach(element => leftNav.appendChild(element));\n\n return resolve(true);\n });\n }\n /**\n * Set the correct active element.\n */\n function setNav() {\n return new Promise(resolve => {\n if (!document.querySelectorAll(nav)) return resolve(true);\n for (const a of document.querySelectorAll(nav)) {\n if (a instanceof HTMLAnchorElement && a.href === location.href) {\n setElementActive(a);\n break;\n }\n }\n resolve(true);\n });\n }\n /** resetNav: removes all .active from nav elements */\n function resetNav() {\n return new Promise(resolve => {\n if (!document.querySelectorAll(nav)) return resolve(true);\n for (const a of document.querySelectorAll(nav)) {\n a.classList.remove('active');\n }\n resolve(true);\n });\n }\n /** setElementActive: controls resetting nav and highlighting the appropriate nav items */\n function setElementActive(element: HTMLAnchorElement) {\n if (element instanceof HTMLAnchorElement) {\n resetNav().then(() => {\n element.classList.add('active');\n const parent = element?.parentNode?.parentNode;\n if (parent instanceof HTMLElement && parent?.classList?.contains('LeftSubnav')) {\n parent.previousElementSibling?.classList.add('active');\n }\n });\n }\n }\n /** setLinkManually: disables observer and selects the clicked nav item. */\n function setLinkManually() {\n delayObserver();\n const link = document.querySelector('[href=\"' + location.hash + '\"]');\n if (link instanceof HTMLAnchorElement) {\n setElementActive(link);\n }\n }\n /** delayObserver: Quick on off switch for intersection observer. */\n function delayObserver() {\n isObserverDisabled = true;\n setTimeout(() => {\n isObserverDisabled = false;\n }, 200);\n }\n /** observeSections: kicks off observation of titles as well as manual clicks with hashchange */\n function observeSections() {\n window.addEventListener('hashchange', setLinkManually);\n\n if (siteContent?.querySelectorAll(titles)) {\n const callback: IntersectionObserverCallback = entries => {\n if (!isObserverDisabled && Array.isArray(entries) && entries.length > 0) {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target instanceof HTMLElement) {\n const { id } = entry.target;\n const link = document.querySelector('[href=\"#' + id + '\"]');\n if (link instanceof HTMLAnchorElement) {\n setElementActive(link);\n }\n break;\n }\n }\n }\n };\n // rootMargin is important when multiple sections are in the observable area **on page load**.\n // they will still be highlighted on scroll because of the root margin.\n const ob = new IntersectionObserver(callback, {\n threshold: 0,\n rootMargin: '0px 0px -50% 0px',\n });\n for (const title of siteContent.querySelectorAll(titles)) {\n if (title instanceof HTMLElement && !title?.dataset?.ignore) {\n ob.observe(title);\n }\n }\n }\n }\n\n try {\n await buildNav();\n await setNav();\n if (location.hash) {\n delayObserver();\n }\n observeSections();\n } catch (e) {\n if (e instanceof Error) {\n console.error(e.message);\n } else {\n console.error(e);\n }\n }\n};\n", "/**\n * @license\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { registerHeaderListeners, registerSearchFormListeners } from 'static/shared/header/header';\nimport { CarouselController } from 'static/shared/carousel/carousel';\nimport { ClipboardController } from 'static/shared/clipboard/clipboard';\nimport { ToolTipController } from 'static/shared/tooltip/tooltip';\nimport { SelectNavController } from 'static/shared/outline/select';\nimport { ModalController } from 'static/shared/modal/modal';\nimport { initModals } from 'static/shared/jump/jump';\n\nimport { keyboard } from 'static/shared/keyboard/keyboard';\nimport * as analytics from 'static/shared/analytics/analytics';\nimport { initJumpLinks } from './about/index';\n\nwindow.addEventListener('load', () => {\n for (const el of document.querySelectorAll('.js-clipboard')) {\n new ClipboardController(el);\n }\n\n for (const el of document.querySelectorAll('.js-modal')) {\n new ModalController(el);\n }\n\n for (const t of document.querySelectorAll('.js-tooltip')) {\n new ToolTipController(t);\n }\n\n for (const el of document.querySelectorAll('.js-selectNav')) {\n new SelectNavController(el);\n }\n\n for (const el of document.querySelectorAll('.js-carousel')) {\n new CarouselController(el);\n }\n\n for (const el of document.querySelectorAll('.js-toggleTheme')) {\n el.addEventListener('click', () => {\n toggleTheme();\n });\n }\n\n if (document.querySelector('.js-gtmID')?.dataset.gtmid && window.dataLayer) {\n analytics.func(function () {\n removeUTMSource();\n });\n } else {\n removeUTMSource();\n }\n\n registerHeaderListeners();\n registerSearchFormListeners();\n initModals();\n initJumpLinks();\n registerCookieNotice();\n});\n\n// Pressing '/' focuses the search box\nkeyboard.on('/', 'focus search', e => {\n const searchInput = Array.from(\n document.querySelectorAll('.js-searchFocus')\n ).pop();\n // Favoring the Firefox quick find feature over search input\n // focus. See: https://github.com/golang/go/issues/41093.\n if (searchInput && !window.navigator.userAgent.includes('Firefox')) {\n e.preventDefault();\n searchInput.focus();\n }\n});\n\n// Pressing 'y' changes the browser URL to the canonical URL\n// without triggering a reload.\nkeyboard.on('y', 'set canonical url', () => {\n let canonicalURLPath = document.querySelector('.js-canonicalURLPath')?.dataset[\n 'canonicalUrlPath'\n ];\n if (canonicalURLPath && canonicalURLPath !== '') {\n const fragment = window.location.hash;\n if (fragment) {\n canonicalURLPath += fragment;\n }\n window.history.replaceState(null, '', canonicalURLPath);\n }\n});\n\n/**\n * setupGoogleTagManager initializes Google Tag Manager.\n */\n(function setupGoogleTagManager() {\n analytics.track({\n 'gtm.start': new Date().getTime(),\n event: 'gtm.js',\n });\n})();\n\n/**\n * removeUTMSource removes the utm_source GET parameter if present.\n * This is done using JavaScript, so that the utm_source is still\n * captured by Google Analytics.\n */\nfunction removeUTMSource() {\n const urlParams = new URLSearchParams(window.location.search);\n const utmSource = urlParams.get('utm_source');\n if (utmSource !== 'gopls' && utmSource !== 'godoc' && utmSource !== 'pkggodev') {\n return;\n }\n\n /** Strip the utm_source query parameter and replace the URL. **/\n const newURL = new URL(window.location.href);\n urlParams.delete('utm_source');\n newURL.search = urlParams.toString();\n window.history.replaceState(null, '', newURL.toString());\n}\n\n/**\n * toggleTheme switches the preferred color scheme between auto, light, and dark.\n */\nfunction toggleTheme() {\n let nextTheme = 'dark';\n const theme = document.documentElement.getAttribute('data-theme');\n if (theme === 'dark') {\n nextTheme = 'light';\n } else if (theme === 'light') {\n nextTheme = 'auto';\n }\n let domain = '';\n if (location.hostname === 'go.dev' || location.hostname.endsWith('.go.dev')) {\n domain = 'domain=.go.dev;';\n }\n document.documentElement.setAttribute('data-theme', nextTheme);\n document.cookie = `prefers-color-scheme=${nextTheme};${domain}path=/;max-age=31536000;`;\n}\n\n/**\n * registerCookieNotice makes the cookie notice visible and adds listeners to dismiss it\n * if it has not yet been acknowledge by the user.\n */\nfunction registerCookieNotice() {\n const themeCookie = document.cookie.match(/cookie-consent=true/);\n if (!themeCookie) {\n const notice = document.querySelector('.js-cookieNotice');\n const button = notice?.querySelector('button');\n notice?.classList.add('Cookie-notice--visible');\n button?.addEventListener('click', () => {\n let domain = '';\n if (location.hostname === 'go.dev' || location.hostname.endsWith('.go.dev')) {\n // Apply the cookie to *.go.dev.\n domain = 'domain=.go.dev;';\n }\n document.cookie = `cookie-consent=true;${domain}path=/;max-age=31536000`;\n notice?.remove();\n });\n }\n}\n"],
+ "sourcesContent": ["/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nexport function registerHeaderListeners(): void {\n const header = document.querySelector('.js-header') as HTMLElement;\n\n // Desktop menu hover state\n const menuItemHovers = document.querySelectorAll('.js-desktop-menu-hover');\n menuItemHovers.forEach(menuItemHover => {\n // when user clicks on the dropdown menu item on desktop or mobile,\n // force the menu to stay open until the user clicks off of it.\n menuItemHover.addEventListener('mouseenter', e => {\n const target = e.target as HTMLElement;\n const forced = document.querySelector('.forced-open') as HTMLElement;\n if (forced && forced !== menuItemHover) {\n forced.blur();\n forced.classList.remove('forced-open');\n }\n // prevents menus that have been tabbed into from staying open\n // when you hover over another menu\n target.classList.remove('forced-closed');\n target.classList.add('forced-open');\n });\n\n const toggleForcedOpen = (e: Event) => {\n const target = e.target as HTMLElement;\n const isForced = target?.classList.contains('forced-open');\n const currentTarget = e.currentTarget as HTMLElement;\n if (isForced) {\n currentTarget.removeEventListener('blur', () =>\n currentTarget.classList.remove('forced-open')\n );\n currentTarget.classList.remove('forced-open');\n currentTarget.classList.add('forced-closed');\n currentTarget.blur();\n currentTarget?.parentNode?.addEventListener('mouseout', () => {\n currentTarget.classList.remove('forced-closed');\n });\n } else {\n currentTarget.classList.remove('forced-closed');\n currentTarget.classList.add('forced-open');\n currentTarget.focus();\n currentTarget.addEventListener('blur', () => currentTarget.classList.remove('forced-open'));\n currentTarget?.parentNode?.removeEventListener('mouseout', () => {\n currentTarget.classList.remove('forced-closed');\n });\n }\n currentTarget.focus();\n };\n menuItemHover.addEventListener('click', toggleForcedOpen);\n menuItemHover.addEventListener('focus', e => {\n const target = e.target as HTMLElement;\n target.classList.add('forced-closed');\n target.classList.remove('forced-open');\n });\n\n // ensure desktop submenus are closed when esc is pressed\n const closeSubmenuOnEsc = (e: Event) => {\n const event = e as KeyboardEvent;\n const target = e.target as HTMLElement;\n if (event.key === 'Escape') {\n const forcedOpenItem = document.querySelector('.forced-open') as HTMLElement;\n if (forcedOpenItem) {\n forcedOpenItem.classList.remove('forced-open');\n forcedOpenItem.blur();\n forcedOpenItem.classList.add('forced-closed');\n target?.focus();\n }\n }\n };\n document.addEventListener('keydown', closeSubmenuOnEsc);\n });\n\n // Mobile menu subnav menus\n const headerbuttons = document.querySelectorAll('.js-headerMenuButton');\n headerbuttons.forEach(button => {\n button.addEventListener('click', e => {\n e.preventDefault();\n const isActive = header?.classList.contains('is-active');\n if (isActive) {\n handleNavigationDrawerInactive(header);\n } else {\n handleNavigationDrawerActive(header);\n }\n button.setAttribute('aria-expanded', isActive ? 'true' : 'false');\n });\n });\n\n const scrim = document.querySelector('.js-scrim');\n scrim?.addEventListener('click', e => {\n e.preventDefault();\n\n // find any active submenus and close them\n const activeSubnavs = document.querySelectorAll('.go-NavigationDrawer-submenuItem.is-active');\n activeSubnavs.forEach(subnav => handleNavigationDrawerInactive(subnav as HTMLElement));\n\n handleNavigationDrawerInactive(header);\n\n headerbuttons.forEach(button => {\n button.setAttribute(\n 'aria-expanded',\n header?.classList.contains('is-active') ? 'true' : 'false'\n );\n });\n });\n\n const getNavigationDrawerMenuItems = (navigationDrawer: HTMLElement): HTMLElement[] => {\n if (!navigationDrawer) {\n return [];\n }\n\n const menuItems = Array.from(\n navigationDrawer.querySelectorAll(\n ':scope > .go-NavigationDrawer-nav > .go-NavigationDrawer-list > .go-NavigationDrawer-listItem > a, :scope > .go-NavigationDrawer-nav > .go-NavigationDrawer-list > .go-NavigationDrawer-listItem > .go-Header-socialIcons > a'\n ) || []\n );\n\n const anchorEl = navigationDrawer.querySelector('.go-NavigationDrawer-header > a');\n if (anchorEl) {\n menuItems.unshift(anchorEl);\n }\n return menuItems as HTMLElement[];\n };\n\n const getNavigationDrawerIsSubnav = (navigationDrawer: HTMLElement) => {\n if (!navigationDrawer) {\n return;\n }\n return navigationDrawer.classList.contains('go-NavigationDrawer-submenuItem');\n };\n\n const handleNavigationDrawerInactive = (navigationDrawer: HTMLElement) => {\n if (!navigationDrawer) {\n return;\n }\n const menuItems = getNavigationDrawerMenuItems(navigationDrawer);\n navigationDrawer.classList.remove('is-active');\n const parentMenuItem = navigationDrawer\n .closest('.go-NavigationDrawer-listItem')\n ?.querySelector(':scope > a') as HTMLElement;\n parentMenuItem?.focus();\n menuItems?.forEach(item => item?.setAttribute('tabindex', '-1'));\n if (menuItems && menuItems[0]) {\n menuItems[0].removeEventListener('keydown', handleMenuItemTabLeftFactory(navigationDrawer));\n menuItems[menuItems.length - 1].removeEventListener(\n 'keydown',\n handleMenuItemTabRightFactory(navigationDrawer)\n );\n }\n\n if (navigationDrawer === header) {\n headerbuttons && (headerbuttons[0] as HTMLElement)?.focus();\n }\n };\n\n const handleNavigationDrawerActive = (navigationDrawer: HTMLElement) => {\n const menuItems = getNavigationDrawerMenuItems(navigationDrawer);\n\n navigationDrawer.classList.add('is-active');\n menuItems.forEach(item => item.setAttribute('tabindex', '0'));\n menuItems[0].focus();\n\n menuItems[0].addEventListener('keydown', handleMenuItemTabLeftFactory(navigationDrawer));\n menuItems[menuItems.length - 1].addEventListener(\n 'keydown',\n handleMenuItemTabRightFactory(navigationDrawer)\n );\n };\n\n const handleMenuItemTabLeftFactory = (navigationDrawer: HTMLElement) => {\n return (e: KeyboardEvent) => {\n if (e.key === 'Tab' && e.shiftKey) {\n e.preventDefault();\n handleNavigationDrawerInactive(navigationDrawer);\n }\n };\n };\n\n const handleMenuItemTabRightFactory = (navigationDrawer: HTMLElement) => {\n return (e: KeyboardEvent) => {\n if (e.key === 'Tab' && !e.shiftKey) {\n e.preventDefault();\n handleNavigationDrawerInactive(navigationDrawer);\n }\n };\n };\n\n const prepMobileNavigationDrawer = (navigationDrawer: HTMLElement) => {\n const isSubnav = getNavigationDrawerIsSubnav(navigationDrawer);\n const menuItems = getNavigationDrawerMenuItems(navigationDrawer);\n navigationDrawer.addEventListener('keyup', e => {\n if (e.key === 'Escape') {\n handleNavigationDrawerInactive(navigationDrawer);\n }\n });\n\n menuItems.forEach(item => {\n const parentLi = item.closest('li');\n if (parentLi && parentLi.classList.contains('js-mobile-subnav-trigger')) {\n const submenu = parentLi.querySelector('.go-NavigationDrawer-submenuItem') as HTMLElement;\n item.addEventListener('click', () => {\n handleNavigationDrawerActive(submenu);\n });\n }\n });\n if (isSubnav) {\n handleNavigationDrawerInactive(navigationDrawer);\n navigationDrawer\n ?.querySelector('.go-NavigationDrawer-header')\n ?.addEventListener('click', e => {\n e.preventDefault();\n handleNavigationDrawerInactive(navigationDrawer);\n });\n }\n };\n\n document\n .querySelectorAll('.go-NavigationDrawer')\n .forEach(drawer => prepMobileNavigationDrawer(drawer as HTMLElement));\n\n handleNavigationDrawerInactive(header);\n}\n\nexport function registerSearchFormListeners(): void {\n const searchForm = document.querySelector('.js-searchForm');\n const expandSearch = document.querySelector('.js-expandSearch');\n const input = searchForm?.querySelector('input');\n const headerLogo = document.querySelector('.js-headerLogo');\n const menuButton = document.querySelector('.js-headerMenuButton');\n expandSearch?.addEventListener('click', () => {\n searchForm?.classList.add('go-SearchForm--expanded');\n headerLogo?.classList.add('go-Header-logo--hidden');\n menuButton?.classList.add('go-Header-navOpen--hidden');\n input?.focus();\n });\n document?.addEventListener('click', e => {\n if (!searchForm?.contains(e.target as Node)) {\n searchForm?.classList.remove('go-SearchForm--expanded');\n headerLogo?.classList.remove('go-Header-logo--hidden');\n menuButton?.classList.remove('go-Header-navOpen--hidden');\n }\n });\n}\n", "/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/pkgsitex \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/pkgsitex\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/pkgsitex/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/pkgsitex/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { getBasePath } from '../base-path/base-path';\n\n/**\n * Carousel Controller adds event listeners, accessibility enhancements, and\n * control elements to a carousel component.\n */\nexport class CarouselController {\n /**\n * slides is a collection of slides in the carousel.\n */\n private slides: HTMLLIElement[];\n /**\n * dots is a collection of dot navigation controls, added to the carousel\n * by this controller.\n */\n private dots: HTMLElement[];\n /**\n * liveRegion is a visually hidden element that notifies assitive devices\n * of visual changes to the carousel. They are added to the carousel by\n * this controller.\n */\n private liveRegion: HTMLElement;\n /**\n * activeIndex is the 0-index of the currently active slide.\n */\n private activeIndex: number;\n\n constructor(private el: HTMLElement) {\n this.slides = Array.from(el.querySelectorAll('.go-Carousel-slide'));\n this.dots = [];\n this.liveRegion = document.createElement('div');\n this.activeIndex = Number(el.getAttribute('data-slide-index') ?? 0);\n\n this.initSlides();\n this.initArrows();\n this.initDots();\n this.initLiveRegion();\n }\n\n private initSlides() {\n for (const [i, v] of this.slides.entries()) {\n if (i === this.activeIndex) continue;\n v.setAttribute('aria-hidden', 'true');\n }\n }\n\n private initArrows() {\n const arrows = document.createElement('ul');\n arrows.classList.add('go-Carousel-arrows');\n // base path \u901A\u8FC7 [getBasePath]() \u6CE8\u5165\uFF1B\u6302\u6839\u65F6\u8FD4\u7A7A\u5B57\u7B26\u4E32\uFF0C\u5BF9\u4E0A\u6E38\u96F6\u5DEE\u5F02\u3002\n const bp = getBasePath();\n arrows.innerHTML = `\n \n \n \n \n \n \n \n \n \n \n `;\n arrows\n .querySelector('.go-Carousel-prevSlide')\n ?.addEventListener('click', () => this.setActive(this.activeIndex - 1));\n arrows\n .querySelector('.go-Carousel-nextSlide')\n ?.addEventListener('click', () => this.setActive(this.activeIndex + 1));\n this.el.append(arrows);\n }\n\n private initDots() {\n const dots = document.createElement('ul');\n dots.classList.add('go-Carousel-dots');\n for (let i = 0; i < this.slides.length; i++) {\n const li = document.createElement('li');\n const button = document.createElement('button');\n button.classList.add('go-Carousel-dot');\n if (i === this.activeIndex) {\n button.classList.add('go-Carousel-dot--active');\n }\n button.innerHTML = `Slide ${i + 1} `;\n button.addEventListener('click', () => this.setActive(i));\n li.append(button);\n dots.append(li);\n this.dots.push(button);\n }\n this.el.append(dots);\n }\n\n private initLiveRegion() {\n this.liveRegion.setAttribute('aria-live', 'polite');\n this.liveRegion.setAttribute('aria-atomic', 'true');\n this.liveRegion.setAttribute('class', 'go-Carousel-obscured');\n this.liveRegion.textContent = `Slide ${this.activeIndex + 1} of ${this.slides.length}`;\n this.el.appendChild(this.liveRegion);\n }\n\n private setActive = (index: number) => {\n this.activeIndex = (index + this.slides.length) % this.slides.length;\n this.el.setAttribute('data-slide-index', String(this.activeIndex));\n for (const d of this.dots) {\n d.classList.remove('go-Carousel-dot--active');\n }\n this.dots[this.activeIndex].classList.add('go-Carousel-dot--active');\n for (const s of this.slides) {\n s.setAttribute('aria-hidden', 'true');\n }\n this.slides[this.activeIndex].removeAttribute('aria-hidden');\n this.liveRegion.textContent = 'Slide ' + (this.activeIndex + 1) + ' of ' + this.slides.length;\n };\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * This class decorates an element to copy arbitrary data attached via a data-\n * attribute to the clipboard.\n */\nexport class ClipboardController {\n /**\n * The data to be copied to the clipboard.\n */\n private data: string;\n\n /**\n * @param el The element that will trigger copying text to the clipboard. The text is\n * expected to be within its data-to-copy attribute.\n */\n constructor(private el: HTMLButtonElement) {\n this.data = el.dataset['toCopy'] ?? el.innerText;\n // if data-to-copy is empty and the button is part of an input group\n // capture the value of the input.\n if (!this.data && el.parentElement?.classList.contains('go-InputGroup')) {\n this.data = (this.data || el.parentElement?.querySelector('input')?.value) ?? '';\n }\n el.addEventListener('click', e => this.handleCopyClick(e));\n }\n\n /**\n * Handles when the primary element is clicked.\n */\n handleCopyClick(e: MouseEvent): void {\n e.preventDefault();\n const TOOLTIP_SHOW_DURATION_MS = 1000;\n\n // This API is not available on iOS.\n if (!navigator.clipboard) {\n this.showTooltipText('Unable to copy', TOOLTIP_SHOW_DURATION_MS);\n return;\n }\n navigator.clipboard\n .writeText(this.data)\n .then(() => {\n this.showTooltipText('Copied!', TOOLTIP_SHOW_DURATION_MS);\n })\n .catch(() => {\n this.showTooltipText('Unable to copy', TOOLTIP_SHOW_DURATION_MS);\n });\n }\n\n /**\n * Shows the given text in a tooltip for a specified amount of time, in milliseconds.\n */\n showTooltipText(text: string, durationMs: number): void {\n this.el.setAttribute('data-tooltip', text);\n setTimeout(() => this.el.setAttribute('data-tooltip', ''), durationMs);\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * ToolTipController handles closing tooltips on external clicks.\n */\nexport class ToolTipController {\n constructor(private el: HTMLDetailsElement) {\n document.addEventListener('click', e => {\n const insideTooltip = this.el.contains(e.target as Element);\n if (!insideTooltip) {\n this.el.removeAttribute('open');\n }\n });\n\n // Add event listener for \"Escape\" keydown to close tooltip\n this.el.addEventListener('keydown', e => {\n if (e.key === 'Escape') {\n this.el.open = false;\n }\n });\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { TreeNavController } from './tree.js';\n\nexport class SelectNavController {\n constructor(private el: Element) {\n this.el.addEventListener('change', e => {\n const target = e.target as HTMLSelectElement;\n let href = target.value;\n if (!target.value.startsWith('/')) {\n href = '/' + href;\n }\n window.location.href = href;\n });\n }\n}\n\nexport function makeSelectNav(tree: TreeNavController): HTMLLabelElement {\n const label = document.createElement('label');\n label.classList.add('go-Label');\n label.setAttribute('aria-label', 'Menu');\n const select = document.createElement('select');\n select.classList.add('go-Select', 'js-selectNav');\n label.appendChild(select);\n const outline = document.createElement('optgroup');\n outline.label = 'Outline';\n select.appendChild(outline);\n const groupMap: Record = {};\n let group: HTMLOptGroupElement;\n for (const t of tree.treeitems) {\n if (Number(t.depth) > 4) continue;\n if (t.groupTreeitem) {\n group = groupMap[t.groupTreeitem.label];\n if (!group) {\n group = groupMap[t.groupTreeitem.label] = document.createElement('optgroup');\n group.label = t.groupTreeitem.label;\n select.appendChild(group);\n }\n } else {\n group = outline;\n }\n const o = document.createElement('option');\n o.label = t.label;\n o.textContent = t.label;\n o.value = (t.el as HTMLAnchorElement).href.replace(window.location.origin, '').replace('/', '');\n group.appendChild(o);\n }\n tree.addObserver(t => {\n const hash = (t.el as HTMLAnchorElement).hash;\n const value = select.querySelector(`[value$=\"${hash}\"]`)?.value;\n if (value) {\n select.value = value;\n }\n }, 50);\n return label;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\ninterface Window {\n dialogPolyfill?: {\n registerDialog: (el: HTMLDialogElement) => void;\n };\n}\n\ndeclare const window: Window;\n\n/**\n * ModalController registers a dialog element with the polyfill if\n * necessary for the current browser, add adds event listeners to\n * close and open modals.\n */\nexport class ModalController {\n constructor(private el: HTMLDialogElement) {\n if (window.dialogPolyfill) {\n window.dialogPolyfill.registerDialog(el);\n }\n this.init();\n }\n\n init() {\n const button = document.querySelector(`[aria-controls=\"${this.el.id}\"]`);\n if (button) {\n button.addEventListener('click', () => {\n if (this.el.showModal) {\n this.el.showModal();\n } else {\n this.el.setAttribute('opened', 'true');\n }\n this.el.querySelector('input')?.focus();\n });\n }\n for (const btn of this.el.querySelectorAll('[data-modal-close]')) {\n btn.addEventListener('click', () => {\n if (this.el.close) {\n this.el.close();\n } else {\n this.el.removeAttribute('opened');\n }\n });\n }\n }\n}\n", "interface TagManagerEvent {\n /**\n * event is the name of the event, used to filter events in\n * Google Analytics.\n */\n event: string;\n\n /**\n * event_category is a name that you supply as a way to group objects\n * that to analyze. Typically, you will use the same category name\n * multiple times over related UI elements (buttons, links, etc).\n */\n event_category?: string;\n\n /**\n * event_action is used to name the type of event or interaction you\n * want to measure for a particular web object. For example, with a\n * single \"form\" category, you can analyze a number of specific events\n * with this parameter, such as: form entered, form submitted.\n */\n event_action?: string;\n\n /**\n * event_label provide additional information for events that you want\n * to analyze, such as the text label of a link.\n */\n event_label?: string;\n\n /**\n * gtm.start is used to initialize Google Tag Manager.\n */\n 'gtm.start'?: number;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\ndeclare global {\n interface Window {\n dataLayer?: (TagManagerEvent | VoidFunction)[];\n ga?: unknown;\n }\n}\n\n/**\n * track sends events to Google Tag Manager.\n */\nexport function track(\n event: string | TagManagerEvent,\n category?: string,\n action?: string,\n label?: string\n): void {\n window.dataLayer ??= [];\n if (typeof event === 'string') {\n window.dataLayer.push({\n event,\n event_category: category,\n event_action: action,\n event_label: label,\n });\n } else {\n window.dataLayer.push(event);\n }\n}\n\n/**\n * func adds functions to run sequentionally after\n * Google Tag Manager is ready.\n */\nexport function func(fn: () => void): void {\n window.dataLayer ??= [];\n window.dataLayer.push(fn);\n}\n", "/*!\n * @license\n * Copyright 2019-2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { track } from '../analytics/analytics';\n\n/**\n * Options are keyhandler callback options.\n */\ninterface Options {\n /**\n * target is the element the key event should filter on. The\n * default target is the document.\n */\n target?: Element;\n\n /**\n * withMeta specifies if the event callback should fire when\n * the key is pressed with a meta key (ctrl, alt, etc). By\n * default meta keypresses are ignored.\n */\n withMeta?: boolean;\n}\n\n/**\n * KeyHandler is the config for a keyboard event callback.\n */\ninterface KeyHandler extends Options {\n description: string;\n callback: (e: KeyboardEvent) => void;\n}\n\n/**\n * KeyboardController controls event callbacks for sitewide\n * keyboard events. Multiple callbacks can be registered for\n * a single key and by default the controller ignores events\n * for text input targets.\n */\nclass KeyboardController {\n handlers: Record>;\n\n constructor() {\n this.handlers = {};\n document.addEventListener('keydown', e => this.handleKeyPress(e));\n }\n\n /**\n * on registers keyboard event callbacks.\n * @param key the key to register.\n * @param description name of the event.\n * @param callback event callback.\n * @param options set target and withMeta options to override the default behaviors.\n */\n on(key: string, description: string, callback: (e: KeyboardEvent) => void, options?: Options) {\n this.handlers[key] ??= new Set();\n this.handlers[key].add({ description, callback, ...options });\n return this;\n }\n\n private handleKeyPress(e: KeyboardEvent) {\n for (const handler of this.handlers[e.key.toLowerCase()] ?? new Set()) {\n if (handler.target && handler.target !== e.target) {\n return;\n }\n const t = e.target as HTMLElement | null;\n if (\n !handler.target &&\n (t?.tagName === 'INPUT' || t?.tagName === 'SELECT' || t?.tagName === 'TEXTAREA')\n ) {\n return;\n }\n if (t?.isContentEditable) {\n return;\n }\n if (\n (handler.withMeta && !(e.ctrlKey || e.metaKey)) ||\n (!handler.withMeta && (e.ctrlKey || e.metaKey))\n ) {\n return;\n }\n track('keypress', 'hotkeys', `${e.key} pressed`, handler.description);\n handler.callback(e);\n }\n }\n}\n\nexport const keyboard = new KeyboardController();\n", "/*!\n * @license\n * Copyright 2019-2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the behavior of the \"jump to symbol\" dialog for Go\n// package documentation, as well as the simple dialog that displays keyboard\n// shortcuts.\n\n// The DOM for the dialogs is at the bottom of static/frontend/unit/main/_modals.tmpl.\n// The CSS is in static/frontend/unit/main/_modals.css.\n\n// The dialog is activated by pressing the 'f' key. It presents a list\n// (#JumpDialog-list) of all Go symbols displayed in the documentation.\n// Entering text in the dialog's text box (#JumpDialog-filter) restricts the\n// list to symbols containing the text. Clicking on an symbol jumps to\n// its documentation.\n\n// This code is based on\n// https://go.googlesource.com/gddo/+/refs/heads/master/gddo-server/assets/site.js.\n// It was modified to remove the dependence on jquery and bootstrap.\n\nimport { keyboard } from '../keyboard/keyboard';\n\nexport function initModals(): void {\n const jumpDialog = document.querySelector('.JumpDialog');\n const jumpBody = jumpDialog?.querySelector('.JumpDialog-body');\n const jumpList = jumpDialog?.querySelector('.JumpDialog-list');\n const jumpFilter = jumpDialog?.querySelector('.JumpDialog-input');\n const doc = document.querySelector('.js-documentation');\n\n interface JumpListItem {\n link: HTMLAnchorElement;\n name: string;\n kind: string;\n lower: string;\n }\n\n let jumpListItems: JumpListItem[] | undefined; // All the symbols in the doc; computed only once.\n\n // collectJumpListItems returns a list of items, one for each symbol in the\n // documentation on the current page.\n //\n // It uses the data-kind attribute generated in the documentation HTML to find\n // the symbols and their id attributes.\n //\n // If there are no data-kind attributes, then we have older doc; fall back to\n // a less precise method.\n function collectJumpListItems() {\n const items = [];\n if (!doc) return;\n for (const el of doc.querySelectorAll('[data-kind]')) {\n items.push(newJumpListItem(el));\n }\n\n // Clicking on any of the links closes the dialog.\n for (const item of items) {\n item.link.addEventListener('click', function () {\n jumpDialog?.close();\n });\n }\n // Sort case-insensitively by symbol name.\n items.sort(function (a, b) {\n return a.lower.localeCompare(b.lower);\n });\n return items;\n }\n\n // newJumpListItem creates a new item for the DOM element el.\n // An item is an object with:\n // - name: the element's id (which is the symbol name)\n // - kind: the element's kind (function, variable, etc.),\n // - link: a link ('a' tag) to the element\n // - lower: the name in lower case, just for sorting\n function newJumpListItem(el: Element): JumpListItem {\n const a = document.createElement('a');\n const name = el.getAttribute('id');\n a.setAttribute('href', '#' + name);\n a.setAttribute('tabindex', '-1');\n a.setAttribute('data-gtmc', 'jump to link');\n const kind = el.getAttribute('data-kind');\n return {\n link: a,\n name: name ?? '',\n kind: kind ?? '',\n lower: name?.toLowerCase() ?? '', // for sorting\n };\n }\n\n let lastFilterValue: string; // The last contents of the filter text box.\n let activeJumpItem = -1; // The index of the currently active item in the list.\n\n // updateJumpList sets the elements of the dialog list to\n // everything whose name contains filter.\n function updateJumpList(filter: string) {\n lastFilterValue = filter;\n if (!jumpListItems) {\n jumpListItems = collectJumpListItems();\n }\n setActiveJumpItem(-1);\n\n // Remove all children from list.\n while (jumpList?.firstChild) {\n jumpList.firstChild.remove();\n }\n\n if (filter) {\n // A filter is set. We treat the filter as a substring that can appear in\n // an item name (case insensitive), and find the following matches - in\n // order of priority:\n //\n // 1. Exact matches (the filter matches the item's name exactly)\n // 2. Prefix matches (the item's name starts with filter)\n // 3. Infix matches (the filter is a substring of the item's name)\n const filterLowerCase = filter.toLowerCase();\n\n const exactMatches = [];\n const prefixMatches = [];\n const infixMatches = [];\n\n // makeLinkHtml creates the link name HTML for a list item. item is the DOM\n // item. item.name.substr(boldStart, boldEnd) will be bolded.\n const makeLinkHtml = (item: JumpListItem, boldStart: number, boldEnd: number) => {\n return (\n item.name.substring(0, boldStart) +\n '' +\n item.name.substring(boldStart, boldEnd) +\n ' ' +\n item.name.substring(boldEnd)\n );\n };\n\n for (const item of jumpListItems ?? []) {\n const nameLowerCase = item.name.toLowerCase();\n\n if (nameLowerCase === filterLowerCase) {\n item.link.innerHTML = makeLinkHtml(item, 0, item.name.length);\n exactMatches.push(item);\n } else if (nameLowerCase.startsWith(filterLowerCase)) {\n item.link.innerHTML = makeLinkHtml(item, 0, filter.length);\n prefixMatches.push(item);\n } else {\n const index = nameLowerCase.indexOf(filterLowerCase);\n if (index > -1) {\n item.link.innerHTML = makeLinkHtml(item, index, index + filter.length);\n infixMatches.push(item);\n }\n }\n }\n\n for (const item of exactMatches.concat(prefixMatches).concat(infixMatches)) {\n jumpList?.appendChild(item.link);\n }\n } else {\n if (!jumpListItems || jumpListItems.length === 0) {\n const msg = document.createElement('i');\n msg.innerHTML = 'There are no symbols on this page.';\n jumpList?.appendChild(msg);\n }\n // No filter set; display all items in their existing order.\n for (const item of jumpListItems ?? []) {\n item.link.innerHTML = item.name + ' ' + item.kind + ' ';\n jumpList?.appendChild(item.link);\n }\n }\n\n if (jumpBody) {\n jumpBody.scrollTop = 0;\n }\n if (jumpListItems?.length && jumpList && jumpList.children.length > 0) {\n setActiveJumpItem(0);\n }\n }\n\n // Set the active jump item to n.\n function setActiveJumpItem(n: number) {\n const cs = jumpList?.children as HTMLCollectionOf | null | undefined;\n if (!cs || !jumpBody) {\n return;\n }\n if (activeJumpItem >= 0) {\n cs[activeJumpItem].classList.remove('JumpDialog-active');\n }\n if (n >= cs.length) {\n n = cs.length - 1;\n }\n if (n >= 0) {\n cs[n].classList.add('JumpDialog-active');\n\n // Scroll so the active item is visible.\n // For some reason cs[n].scrollIntoView() doesn't behave as I'd expect:\n // it moves the entire dialog box in the viewport.\n\n // Get the top and bottom of the active item relative to jumpBody.\n const activeTop = cs[n].offsetTop - cs[0].offsetTop;\n const activeBottom = activeTop + cs[n].clientHeight;\n if (activeTop < jumpBody.scrollTop) {\n // Off the top; scroll up.\n jumpBody.scrollTop = activeTop;\n } else if (activeBottom > jumpBody.scrollTop + jumpBody.clientHeight) {\n // Off the bottom; scroll down.\n jumpBody.scrollTop = activeBottom - jumpBody.clientHeight;\n }\n }\n activeJumpItem = n;\n }\n\n // Increment the activeJumpItem by delta.\n function incActiveJumpItem(delta: number) {\n if (activeJumpItem < 0) {\n return;\n }\n let n = activeJumpItem + delta;\n if (n < 0) {\n n = 0;\n }\n setActiveJumpItem(n);\n }\n\n // Pressing a key in the filter updates the list (if the filter actually changed).\n jumpFilter?.addEventListener('keyup', function () {\n if (jumpFilter.value.toUpperCase() != lastFilterValue.toUpperCase()) {\n updateJumpList(jumpFilter.value);\n }\n });\n\n // Pressing enter in the filter selects the first element in the list.\n jumpFilter?.addEventListener('keydown', function (event) {\n const upArrow = 38;\n const downArrow = 40;\n const enterKey = 13;\n switch (event.which) {\n case upArrow:\n incActiveJumpItem(-1);\n event.preventDefault();\n break;\n case downArrow:\n incActiveJumpItem(1);\n event.preventDefault();\n break;\n case enterKey:\n if (activeJumpItem >= 0) {\n if (jumpList) {\n (jumpList.children[activeJumpItem] as HTMLElement).click();\n event.preventDefault();\n }\n }\n break;\n }\n });\n\n const shortcutsDialog = document.querySelector('.ShortcutsDialog');\n\n // - Pressing 'f' or 'F' opens the jump-to-symbol dialog.\n // - Pressing '?' opens up the shortcut dialog.\n // Ignore a keypress if a dialog is already open, or if it is pressed on a\n // component that wants to consume it.\n keyboard\n .on('f', 'open jump to modal', e => {\n if (jumpDialog?.open || shortcutsDialog?.open) {\n return;\n }\n e.preventDefault();\n if (jumpFilter) {\n jumpFilter.value = '';\n }\n jumpDialog?.showModal?.();\n jumpFilter?.focus();\n updateJumpList('');\n })\n .on('?', 'open shortcuts modal', () => {\n if (jumpDialog?.open || shortcutsDialog?.open) {\n return;\n }\n shortcutsDialog?.showModal?.();\n });\n\n const jumpOutlineInput = document.querySelector('.js-jumpToInput');\n if (jumpOutlineInput) {\n jumpOutlineInput.addEventListener('click', () => {\n if (jumpFilter) {\n jumpFilter.value = '';\n }\n updateJumpList('');\n if (jumpDialog?.open || shortcutsDialog?.open) {\n return;\n }\n jumpDialog?.showModal?.();\n jumpFilter?.focus();\n });\n }\n\n document.querySelector('.js-openShortcuts')?.addEventListener('click', () => {\n shortcutsDialog?.showModal?.();\n });\n}\n", "/**\n * @license\n * Copyright 2022 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { abs } from '../../shared/base-path/base-path';\n\n/**\n * Left Navigation.\n */\nexport const initJumpLinks = async function () {\n // pathname \u5728\u6302 -base-path=/pkgsitex \u65F6\u662F \"/pkgsitex/about\"\u2014\u2014\u6BD4\u8F83\u5217\u8868\u4E5F\u5F97\u5E26\u524D\u7F00\n const pagesWithJumpLinks = [abs('/about')];\n if (!pagesWithJumpLinks.includes(window.location.pathname)) {\n // stop the file from doing anything else if the page doesn't have jumplinks\n return;\n }\n\n // these might be generated or not so don't grab references to the elements until actually need them.\n const titles = 'h2, h3, h4';\n const nav = '.LeftNav a';\n // these are always in the dom so we can get them now and throw errors if they're not.\n const leftNav = document.querySelector('.LeftNav');\n const siteContent = document.querySelector('.go-Content');\n let isObserverDisabled = false;\n\n /**\n * El function\n * @example el('h1', {className: 'title'}, 'Welcome to the site');\n * @example el('ul', {className: 'list'}, el('li', {}, 'Item one'), el('li', {}, 'Item two'), el('li', {}, 'Item three'));\n * @example el('img', {src: '/url.svg'});\n */\n function el(\n type = '',\n props: { [key: string]: string } = {},\n ...children: (HTMLElement | HTMLElement[] | string | undefined)[]\n ) {\n // Error, no type declared.\n if (!type) {\n throw new Error('Provide `type` to create document element.');\n }\n\n // Create element with optional attribute props\n const docEl = Object.assign(document.createElement(type), props);\n\n // Children: array containing strings or elements\n children.forEach(child => {\n if (typeof child === 'string') {\n docEl.appendChild(document.createTextNode(child));\n } else if (Array.isArray(child)) {\n child.forEach(c => docEl.appendChild(c));\n } else if (child instanceof HTMLElement) {\n docEl.appendChild(child);\n }\n });\n\n return docEl;\n }\n /** Build Nav if data hydrate is present. */\n function buildNav() {\n return new Promise((resolve, reject) => {\n let navItems: { id: string; label: string; subnav?: { id: string; label: string }[] }[] = [];\n let elements: HTMLElement[] = [];\n\n if (!siteContent || !leftNav) {\n return reject('.SiteContent not found.');\n }\n if (leftNav instanceof HTMLElement && !leftNav?.dataset?.hydrate) {\n return resolve(true);\n }\n\n for (const title of siteContent.querySelectorAll(titles)) {\n if (title instanceof HTMLElement && !title?.dataset?.ignore) {\n switch (title.tagName) {\n case 'H2':\n navItems = [\n ...navItems,\n {\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n },\n ];\n break;\n\n case 'H3':\n case 'H4':\n if (!navItems[navItems.length - 1]?.subnav) {\n navItems[navItems.length - 1].subnav = [\n {\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n },\n ];\n } else if (navItems[navItems.length - 1].subnav) {\n navItems[navItems.length - 1].subnav?.push({\n id: title.id,\n label: title?.dataset?.title ? title.dataset.title : title.textContent ?? '',\n });\n }\n break;\n }\n }\n }\n\n for (const navItem of navItems) {\n const link = el('a', { href: '#' + navItem.id }, el('span', {}, navItem.label));\n elements = [...elements, link];\n if (navItem?.subnav) {\n let subLinks: HTMLElement[] = [];\n for (const subnavItem of navItem.subnav) {\n const subItem = el(\n 'li',\n {},\n el(\n 'a',\n { href: '#' + subnavItem.id },\n el('img', { src: abs('/static/frontend/about/dot.svg'), width: '5', height: '5' }),\n el('span', {}, subnavItem.label)\n )\n );\n subLinks = [...subLinks, subItem];\n }\n const list = el('ul', { className: 'LeftSubnav' }, subLinks);\n elements = [...elements, list];\n }\n }\n\n elements.forEach(element => leftNav.appendChild(element));\n\n return resolve(true);\n });\n }\n /**\n * Set the correct active element.\n */\n function setNav() {\n return new Promise(resolve => {\n if (!document.querySelectorAll(nav)) return resolve(true);\n for (const a of document.querySelectorAll(nav)) {\n if (a instanceof HTMLAnchorElement && a.href === location.href) {\n setElementActive(a);\n break;\n }\n }\n resolve(true);\n });\n }\n /** resetNav: removes all .active from nav elements */\n function resetNav() {\n return new Promise(resolve => {\n if (!document.querySelectorAll(nav)) return resolve(true);\n for (const a of document.querySelectorAll(nav)) {\n a.classList.remove('active');\n }\n resolve(true);\n });\n }\n /** setElementActive: controls resetting nav and highlighting the appropriate nav items */\n function setElementActive(element: HTMLAnchorElement) {\n if (element instanceof HTMLAnchorElement) {\n resetNav().then(() => {\n element.classList.add('active');\n const parent = element?.parentNode?.parentNode;\n if (parent instanceof HTMLElement && parent?.classList?.contains('LeftSubnav')) {\n parent.previousElementSibling?.classList.add('active');\n }\n });\n }\n }\n /** setLinkManually: disables observer and selects the clicked nav item. */\n function setLinkManually() {\n delayObserver();\n const link = document.querySelector('[href=\"' + location.hash + '\"]');\n if (link instanceof HTMLAnchorElement) {\n setElementActive(link);\n }\n }\n /** delayObserver: Quick on off switch for intersection observer. */\n function delayObserver() {\n isObserverDisabled = true;\n setTimeout(() => {\n isObserverDisabled = false;\n }, 200);\n }\n /** observeSections: kicks off observation of titles as well as manual clicks with hashchange */\n function observeSections() {\n window.addEventListener('hashchange', setLinkManually);\n\n if (siteContent?.querySelectorAll(titles)) {\n const callback: IntersectionObserverCallback = entries => {\n if (!isObserverDisabled && Array.isArray(entries) && entries.length > 0) {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target instanceof HTMLElement) {\n const { id } = entry.target;\n const link = document.querySelector('[href=\"#' + id + '\"]');\n if (link instanceof HTMLAnchorElement) {\n setElementActive(link);\n }\n break;\n }\n }\n }\n };\n // rootMargin is important when multiple sections are in the observable area **on page load**.\n // they will still be highlighted on scroll because of the root margin.\n const ob = new IntersectionObserver(callback, {\n threshold: 0,\n rootMargin: '0px 0px -50% 0px',\n });\n for (const title of siteContent.querySelectorAll(titles)) {\n if (title instanceof HTMLElement && !title?.dataset?.ignore) {\n ob.observe(title);\n }\n }\n }\n }\n\n try {\n await buildNav();\n await setNav();\n if (location.hash) {\n delayObserver();\n }\n observeSections();\n } catch (e) {\n if (e instanceof Error) {\n console.error(e.message);\n } else {\n console.error(e);\n }\n }\n};\n", "/**\n * @license\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { registerHeaderListeners, registerSearchFormListeners } from 'static/shared/header/header';\nimport { CarouselController } from 'static/shared/carousel/carousel';\nimport { ClipboardController } from 'static/shared/clipboard/clipboard';\nimport { ToolTipController } from 'static/shared/tooltip/tooltip';\nimport { SelectNavController } from 'static/shared/outline/select';\nimport { ModalController } from 'static/shared/modal/modal';\nimport { initModals } from 'static/shared/jump/jump';\n\nimport { keyboard } from 'static/shared/keyboard/keyboard';\nimport * as analytics from 'static/shared/analytics/analytics';\nimport { initJumpLinks } from './about/index';\n\nwindow.addEventListener('load', () => {\n for (const el of document.querySelectorAll('.js-clipboard')) {\n new ClipboardController(el);\n }\n\n for (const el of document.querySelectorAll('.js-modal')) {\n new ModalController(el);\n }\n\n for (const t of document.querySelectorAll('.js-tooltip')) {\n new ToolTipController(t);\n }\n\n for (const el of document.querySelectorAll('.js-selectNav')) {\n new SelectNavController(el);\n }\n\n for (const el of document.querySelectorAll('.js-carousel')) {\n new CarouselController(el);\n }\n\n for (const el of document.querySelectorAll('.js-toggleTheme')) {\n el.addEventListener('click', () => {\n toggleTheme();\n });\n }\n\n if (document.querySelector('.js-gtmID')?.dataset.gtmid && window.dataLayer) {\n analytics.func(function () {\n removeUTMSource();\n });\n } else {\n removeUTMSource();\n }\n\n registerHeaderListeners();\n registerSearchFormListeners();\n initModals();\n initJumpLinks();\n registerCookieNotice();\n});\n\n// Pressing '/' focuses the search box\nkeyboard.on('/', 'focus search', e => {\n const searchInput = Array.from(\n document.querySelectorAll('.js-searchFocus')\n ).pop();\n // Favoring the Firefox quick find feature over search input\n // focus. See: https://github.com/golang/go/issues/41093.\n if (searchInput && !window.navigator.userAgent.includes('Firefox')) {\n e.preventDefault();\n searchInput.focus();\n }\n});\n\n// Pressing 'y' changes the browser URL to the canonical URL\n// without triggering a reload.\nkeyboard.on('y', 'set canonical url', () => {\n let canonicalURLPath = document.querySelector('.js-canonicalURLPath')?.dataset[\n 'canonicalUrlPath'\n ];\n if (canonicalURLPath && canonicalURLPath !== '') {\n const fragment = window.location.hash;\n if (fragment) {\n canonicalURLPath += fragment;\n }\n window.history.replaceState(null, '', canonicalURLPath);\n }\n});\n\n/**\n * setupGoogleTagManager initializes Google Tag Manager.\n */\n(function setupGoogleTagManager() {\n analytics.track({\n 'gtm.start': new Date().getTime(),\n event: 'gtm.js',\n });\n})();\n\n/**\n * removeUTMSource removes the utm_source GET parameter if present.\n * This is done using JavaScript, so that the utm_source is still\n * captured by Google Analytics.\n */\nfunction removeUTMSource() {\n const urlParams = new URLSearchParams(window.location.search);\n const utmSource = urlParams.get('utm_source');\n if (utmSource !== 'gopls' && utmSource !== 'godoc' && utmSource !== 'pkggodev') {\n return;\n }\n\n /** Strip the utm_source query parameter and replace the URL. **/\n const newURL = new URL(window.location.href);\n urlParams.delete('utm_source');\n newURL.search = urlParams.toString();\n window.history.replaceState(null, '', newURL.toString());\n}\n\n/**\n * toggleTheme switches the preferred color scheme between auto, light, and dark.\n */\nfunction toggleTheme() {\n let nextTheme = 'dark';\n const theme = document.documentElement.getAttribute('data-theme');\n if (theme === 'dark') {\n nextTheme = 'light';\n } else if (theme === 'light') {\n nextTheme = 'auto';\n }\n let domain = '';\n if (location.hostname === 'go.dev' || location.hostname.endsWith('.go.dev')) {\n domain = 'domain=.go.dev;';\n }\n document.documentElement.setAttribute('data-theme', nextTheme);\n document.cookie = `prefers-color-scheme=${nextTheme};${domain}path=/;max-age=31536000;`;\n}\n\n/**\n * registerCookieNotice makes the cookie notice visible and adds listeners to dismiss it\n * if it has not yet been acknowledge by the user.\n */\nfunction registerCookieNotice() {\n const themeCookie = document.cookie.match(/cookie-consent=true/);\n if (!themeCookie) {\n const notice = document.querySelector('.js-cookieNotice');\n const button = notice?.querySelector('button');\n notice?.classList.add('Cookie-notice--visible');\n button?.addEventListener('click', () => {\n let domain = '';\n if (location.hostname === 'go.dev' || location.hostname.endsWith('.go.dev')) {\n // Apply the cookie to *.go.dev.\n domain = 'domain=.go.dev;';\n }\n document.cookie = `cookie-consent=true;${domain}path=/;max-age=31536000`;\n notice?.remove();\n });\n }\n}\n"],
"mappings": "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",
"names": ["registerHeaderListeners", "header", "menuItemHover", "e", "target", "forced", "toggleForcedOpen", "_a", "_b", "isForced", "currentTarget", "closeSubmenuOnEsc", "event", "forcedOpenItem", "headerbuttons", "button", "isActive", "handleNavigationDrawerInactive", "handleNavigationDrawerActive", "scrim", "subnav", "getNavigationDrawerMenuItems", "navigationDrawer", "menuItems", "anchorEl", "getNavigationDrawerIsSubnav", "parentMenuItem", "item", "handleMenuItemTabLeftFactory", "handleMenuItemTabRightFactory", "prepMobileNavigationDrawer", "isSubnav", "parentLi", "submenu", "drawer", "registerSearchFormListeners", "searchForm", "expandSearch", "input", "headerLogo", "menuButton", "getBasePath", "_a", "abs", "p", "CarouselController", "el", "index", "d", "s", "_a", "i", "v", "_b", "arrows", "bp", "getBasePath", "dots", "li", "button", "ClipboardController", "el", "_a", "_b", "_c", "_d", "_e", "e", "TOOLTIP_SHOW_DURATION_MS", "text", "durationMs", "ToolTipController", "el", "e", "SelectNavController", "el", "e", "target", "href", "ModalController", "el", "button", "_a", "btn", "track", "event", "category", "action", "label", "_a", "func", "fn", "KeyboardController", "key", "description", "callback", "options", "_a", "_b", "handler", "t", "track", "keyboard", "initModals", "_a", "jumpDialog", "jumpBody", "jumpList", "jumpFilter", "doc", "jumpListItems", "collectJumpListItems", "items", "el", "newJumpListItem", "item", "a", "b", "name", "kind", "lastFilterValue", "activeJumpItem", "updateJumpList", "filter", "setActiveJumpItem", "filterLowerCase", "exactMatches", "prefixMatches", "infixMatches", "makeLinkHtml", "boldStart", "boldEnd", "nameLowerCase", "index", "msg", "n", "cs", "activeTop", "activeBottom", "incActiveJumpItem", "delta", "event", "shortcutsDialog", "keyboard", "e", "jumpOutlineInput", "initJumpLinks", "abs", "titles", "nav", "leftNav", "siteContent", "isObserverDisabled", "el", "type", "props", "children", "docEl", "child", "c", "buildNav", "resolve", "reject", "_a", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "navItems", "elements", "title", "navItem", "link", "subLinks", "subnavItem", "subItem", "list", "element", "setNav", "a", "setElementActive", "resetNav", "parent", "setLinkManually", "delayObserver", "observeSections", "callback", "entries", "entry", "id", "ob", "e", "_a", "el", "ClipboardController", "ModalController", "t", "ToolTipController", "SelectNavController", "CarouselController", "toggleTheme", "func", "removeUTMSource", "registerHeaderListeners", "registerSearchFormListeners", "initModals", "initJumpLinks", "registerCookieNotice", "keyboard", "e", "searchInput", "canonicalURLPath", "fragment", "track", "urlParams", "utmSource", "newURL", "nextTheme", "theme", "domain", "notice", "button"]
}
diff --git a/static/frontend/unit/main/main.js b/static/frontend/unit/main/main.js
index c1a1cbba7..3ad82aff2 100644
--- a/static/frontend/unit/main/main.js
+++ b/static/frontend/unit/main/main.js
@@ -3,7 +3,7 @@ function H(){var l;return(l=document.documentElement.dataset.basePath)!=null?l:"
module play.ground
require ${t.modulepath} ${t.version}
-`)),e}handleShareButtonClick(){let e="https://play.golang.org/p/";this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/share"),{method:"POST",body:this.getCodeWithModFile()}).then(t=>t.text()).then(t=>{let i=e+t;this.setOutputHTML(`${i} `),window.open(i)}).catch(t=>{this.setErrorText(t)})}handleFormatButtonClick(){var t,i;this.setOutputText("Waiting for remote server\u2026");let e=new FormData;e.append("body",(i=(t=this.inputEl)==null?void 0:t.value)!=null?i:""),fetch(p("/play/fmt"),{method:"POST",body:e}).then(s=>s.json()).then(({Body:s,Error:n})=>{this.setOutputText(n||"Done."),s&&(this.setInputText(s),this.resize())}).catch(s=>{this.setErrorText(s)})}handleRunButtonClick(){this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/compile"),{method:"POST",body:JSON.stringify({body:this.getCodeWithModFile(),version:2})}).then(e=>e.json()).then(async({Events:e,Errors:t})=>{this.setOutputText(t||"");for(let i of e||[])this.appendToOutputText(i.Message),await new Promise(s=>setTimeout(s,i.Delay/1e6))}).catch(e=>{this.setErrorText(e)})}};function C(){let l=location.hash.match(/^#(example-.*)$/);if(l){let i=document.getElementById(l[1]);i&&(i.open=!0)}let e=[...document.querySelectorAll(u.PLAY_HREF)],t=i=>e.find(s=>s.hash===i.getAnchorHash());for(let i of document.querySelectorAll(u.PLAY_CONTAINER)){let s=new x(i),n=t(s);n?n.addEventListener("click",()=>{s.expand()}):console.warn("example href not found")}}var f=class{constructor(e){this.el=e;this.el.addEventListener("change",t=>{let i=t.target,s=i.value;i.value.startsWith("/")||(s="/"+s),window.location.href=s})}};function I(l){let e=document.createElement("label");e.classList.add("go-Label"),e.setAttribute("aria-label","Menu");let t=document.createElement("select");t.classList.add("go-Select","js-selectNav"),e.appendChild(t);let i=document.createElement("optgroup");i.label="Outline",t.appendChild(i);let s={},n;for(let r of l.treeitems){if(Number(r.depth)>4)continue;r.groupTreeitem?(n=s[r.groupTreeitem.label],n||(n=s[r.groupTreeitem.label]=document.createElement("optgroup"),n.label=r.groupTreeitem.label,t.appendChild(n))):n=i;let a=document.createElement("option");a.label=r.label,a.textContent=r.label,a.value=r.el.href.replace(window.location.origin,"").replace("/",""),n.appendChild(a)}return l.addObserver(r=>{var h;let a=r.el.hash,d=(h=t.querySelector(`[value$="${a}"]`))==null?void 0:h.value;d&&(t.value=d)},50),e}var E=class{constructor(e){this.el=e;this.handleResize=()=>{this.el.style.setProperty("--js-tree-height","100vh"),this.el.style.setProperty("--js-tree-height",this.el.clientHeight+"px")};this.treeitems=[],this.firstChars=[],this.firstTreeitem=null,this.lastTreeitem=null,this.observerCallbacks=[],this.init()}init(){this.handleResize(),window.addEventListener("resize",this.handleResize),this.findTreeItems(),this.updateVisibleTreeitems(),this.observeTargets(),this.firstTreeitem&&(this.firstTreeitem.el.tabIndex=0)}observeTargets(){this.addObserver(i=>{this.expandTreeitem(i),this.setSelected(i)});let e=new Map,t=new IntersectionObserver(i=>{for(let s of i)e.set(s.target.id,s.isIntersecting||s.intersectionRatio===1);for(let[s,n]of e)if(n){let r=this.treeitems.find(a=>{var d;return(d=a.el)==null?void 0:d.href.endsWith(`#${s}`)});if(r)for(let a of this.observerCallbacks)a(r);break}},{threshold:1,rootMargin:"-60px 0px 0px 0px"});for(let i of this.treeitems.map(s=>s.el.getAttribute("href")))if(i){let s=i.replace(window.location.origin,"").replace("/","").replace("#",""),n=document.getElementById(s);n&&!s.startsWith("example-")&&t.observe(n)}}addObserver(e,t=200){this.observerCallbacks.push(O(e,t))}setFocusToNextItem(e){let t=null;for(let i=e.index+1;i-1;i--){let s=this.treeitems[i];if(s.isVisible){t=s;break}}t&&this.setFocusToItem(t)}setFocusToParentItem(e){e.groupTreeitem&&this.setFocusToItem(e.groupTreeitem)}setFocusToFirstItem(){this.firstTreeitem&&this.setFocusToItem(this.firstTreeitem)}setFocusToLastItem(){this.lastTreeitem&&this.setFocusToItem(this.lastTreeitem)}setSelected(e){var t;for(let i of this.el.querySelectorAll('[aria-expanded="true"]'))i!==e.el&&((t=i.nextElementSibling)!=null&&t.contains(e.el)||i.setAttribute("aria-expanded","false"));for(let i of this.el.querySelectorAll("[aria-selected]"))i!==e.el&&i.setAttribute("aria-selected","false");e.el.setAttribute("aria-selected","true"),this.updateVisibleTreeitems(),this.setFocusToItem(e,!1)}expandTreeitem(e){let t=e;for(;t;)t.isExpandable&&t.el.setAttribute("aria-expanded","true"),t=t.groupTreeitem;this.updateVisibleTreeitems()}expandAllSiblingItems(e){for(let t of this.treeitems)t.groupTreeitem===e.groupTreeitem&&t.isExpandable&&this.expandTreeitem(t)}collapseTreeitem(e){let t=null;e.isExpanded()?t=e:t=e.groupTreeitem,t&&(t.el.setAttribute("aria-expanded","false"),this.updateVisibleTreeitems(),this.setFocusToItem(t))}setFocusByFirstCharacter(e,t){let i,s;t=t.toLowerCase(),i=e.index+1,i===this.treeitems.length&&(i=0),s=this.getIndexFirstChars(i,t),s===-1&&(s=this.getIndexFirstChars(0,t)),s>-1&&this.setFocusToItem(this.treeitems[s])}findTreeItems(){let e=(t,i)=>{let s=i,n=t.firstElementChild;for(;n;)(n.tagName==="A"||n.tagName==="SPAN")&&(s=new g(n,this,i),this.treeitems.push(s),this.firstChars.push(s.label.substring(0,1).toLowerCase())),n.firstElementChild&&e(n,s),n=n.nextElementSibling};e(this.el,null),this.treeitems.map((t,i)=>t.index=i)}updateVisibleTreeitems(){this.firstTreeitem=this.treeitems[0];for(let e of this.treeitems){let t=e.groupTreeitem;for(e.isVisible=!0;t&&t.el!==this.el;)t.isExpanded()||(e.isVisible=!1),t=t.groupTreeitem;e.isVisible&&(this.lastTreeitem=e)}}setFocusToItem(e,t=!0){e.el.tabIndex=0,t&&e.el.focus();for(let i of this.treeitems)i!==e&&(i.el.tabIndex=-1)}getIndexFirstChars(e,t){for(let i=e;i{let s=()=>{t=null,l(...i)};t&&clearTimeout(t),t=setTimeout(s,e)}}var T=class{constructor(e,t){this.table=e;this.toggleAll=t;this.expandAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","true")),this.update()};this.collapseAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","false")),this.update()};this.update=()=>{this.updateVisibleItems(),setTimeout(()=>this.updateGlobalToggle())};this.rows=Array.from(e.querySelectorAll("[data-aria-controls]")),this.toggles=Array.from(this.table.querySelectorAll("[aria-expanded]")),this.setAttributes(),this.attachEventListeners(),this.update()}setAttributes(){for(let e of["data-aria-controls","data-aria-labelledby","data-id"])this.table.querySelectorAll(`[${e}]`).forEach(t=>{var i;t.setAttribute(e.replace("data-",""),(i=t.getAttribute(e))!=null?i:""),t.removeAttribute(e)})}attachEventListeners(){var e;this.rows.forEach(t=>{t.addEventListener("click",i=>{this.handleToggleClick(i)})}),(e=this.toggleAll)==null||e.addEventListener("click",()=>{this.expandAllItems()}),document.addEventListener("keydown",t=>{(t.ctrlKey||t.metaKey)&&t.key==="f"&&this.expandAllItems()})}handleToggleClick(e){let t=e.currentTarget;t!=null&&t.hasAttribute("aria-expanded")||(t=this.table.querySelector(`button[aria-controls="${t==null?void 0:t.getAttribute("aria-controls")}"]`));let i=(t==null?void 0:t.getAttribute("aria-expanded"))==="true";t==null||t.setAttribute("aria-expanded",i?"false":"true"),e.stopPropagation(),this.update()}updateVisibleItems(){this.rows.map(e=>{var s;let t=(e==null?void 0:e.getAttribute("aria-expanded"))==="true",i=(s=e==null?void 0:e.getAttribute("aria-controls"))==null?void 0:s.trimEnd().split(" ");i==null||i.map(n=>{let r=document.getElementById(`${n}`);t?(r==null||r.classList.add("visible"),r==null||r.classList.remove("hidden")):(r==null||r.classList.add("hidden"),r==null||r.classList.remove("visible"))})})}updateGlobalToggle(){if(!this.toggleAll)return;this.rows.some(t=>t.hasAttribute("aria-expanded"))&&(this.toggleAll.style.display="block"),this.toggles.some(t=>t.getAttribute("aria-expanded")==="false")?(this.toggleAll.innerText="Expand all",this.toggleAll.onclick=this.expandAllItems,this.toggleAll.setAttribute("aria-label","Expand all directories"),this.toggleAll.setAttribute("aria-live","polite")):(this.toggleAll.innerText="Collapse all",this.toggleAll.onclick=this.collapseAllItems,this.toggleAll.setAttribute("aria-label","Collapse all directories"),this.toggleAll.setAttribute("aria-live","polite"))}};C();var m=document.querySelector(".js-expandableTable");if(m){let l=new T(m,document.querySelector(".js-expandAllDirectories"));window.location.search.includes("expand-directories")&&l.expandAllItems();let e=document.querySelector(".js-showInternalDirectories");e&&(document.querySelector(".UnitDirectories-internal")&&(e.style.display="block",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-describedby","showInternal-description")),e.addEventListener("click",()=>{m.classList.contains("UnitDirectories-showInternal")?(m.classList.remove("UnitDirectories-showInternal"),e.innerText="Show internal",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","showInternal-description")):(m.classList.add("UnitDirectories-showInternal"),e.innerText="Hide internal",e.setAttribute("aria-label","Hide Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","hideInternal-description"))})),document.querySelector('html[data-local="true"]')&&(e==null||e.click())}var S=document.querySelector(".js-tree");if(S){let l=new E(S),e=I(l),t=document.querySelector(".js-mainNavMobile");t&&t.firstElementChild&&(t==null||t.replaceChild(e,t.firstElementChild)),e.firstElementChild&&new f(e.firstElementChild)}var o=document.querySelector(".js-readme"),v=document.querySelector(".js-readmeContent"),w=document.querySelector(".js-readmeOutline"),b=document.querySelectorAll(".js-readmeExpand"),k=document.querySelector(".js-readmeCollapse"),y=document.querySelector(".DocNavMobile-select");o&&v&&w&&b.length&&k&&(o.clientHeight>320&&(o==null||o.classList.remove("UnitReadme--expanded"),o==null||o.classList.add("UnitReadme--toggle")),window.location.hash.includes("readme")&&c(),y==null||y.addEventListener("change",l=>{l.target.value.startsWith("readme-")&&c()}),b.forEach(l=>l.addEventListener("click",e=>{e.preventDefault(),c(),o.scrollIntoView()})),k.addEventListener("click",l=>{l.preventDefault(),o.classList.remove("UnitReadme--expanded"),b[1]&&b[1].scrollIntoView({block:"center"})}),v.addEventListener("keyup",()=>{c()}),v.addEventListener("click",()=>{c()}),w.addEventListener("click",()=>{c()}),document.addEventListener("keydown",l=>{(l.ctrlKey||l.metaKey)&&l.key==="f"&&c()}));function c(){history.replaceState(null,"",`${location.pathname}${location.search}#section-readme`),o==null||o.classList.add("UnitReadme--expanded")}function M(){var t;if(!location.hash)return;let l=document.getElementById(location.hash.slice(1)),e=(t=l==null?void 0:l.parentElement)==null?void 0:t.parentElement;(e==null?void 0:e.nodeName)==="DETAILS"&&(e.open=!0)}M();window.addEventListener("hashchange",()=>M());document.querySelectorAll(".js-buildContextSelect").forEach(l=>{l.addEventListener("change",e=>{window.location.search=`?GOOS=${e.target.value}`})});(()=>{if(!document.querySelector("h4[data-kind]"))return;let l=r=>{var d;if(r.startsWith("pkg-")||r.startsWith("section-")||r.startsWith("hdr-"))return!1;let a=(d=r.split(".").pop())!=null?d:r;return/^[a-z]/.test(a)};document.querySelectorAll("h4[data-kind][id]").forEach(r=>{if(!l(r.id))return;let a=r.closest(".Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod");a==null||a.classList.add("Documentation-unexported")}),document.querySelectorAll('.Documentation-indexFunction a[href^="#"], .Documentation-indexType a[href^="#"], .Documentation-indexTypeFunctions a[href^="#"], .Documentation-indexTypeMethods a[href^="#"], .go-Tree a[href^="#"]').forEach(r=>{var a;l(r.getAttribute("href").slice(1))&&((a=r.closest("li"))==null||a.classList.add("Documentation-unexported"))});let e=document.createElement("style");e.textContent="body:not(.show-unexported) .Documentation-unexported{display:none}",document.head.appendChild(e);let t=document.querySelector("#pkg-index");if(!t)return;let i=document.createElement("button");i.type="button",i.className="go-Button go-Button--inline",i.style.marginLeft="0.75rem",i.style.fontSize="0.875rem",i.style.verticalAlign="middle";let s="gogodocs:showUnexported",n=r=>{document.body.classList.toggle("show-unexported",r),i.textContent=r?"Hide unexported":"Show unexported";try{localStorage.setItem(s,r?"1":"0")}catch{}};n(localStorage.getItem(s)==="1"),i.addEventListener("click",()=>n(!document.body.classList.contains("show-unexported"))),t.appendChild(i)})();
+`)),e}handleShareButtonClick(){let e="https://play.golang.org/p/";this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/share"),{method:"POST",body:this.getCodeWithModFile()}).then(t=>t.text()).then(t=>{let i=e+t;this.setOutputHTML(`${i} `),window.open(i)}).catch(t=>{this.setErrorText(t)})}handleFormatButtonClick(){var t,i;this.setOutputText("Waiting for remote server\u2026");let e=new FormData;e.append("body",(i=(t=this.inputEl)==null?void 0:t.value)!=null?i:""),fetch(p("/play/fmt"),{method:"POST",body:e}).then(s=>s.json()).then(({Body:s,Error:n})=>{this.setOutputText(n||"Done."),s&&(this.setInputText(s),this.resize())}).catch(s=>{this.setErrorText(s)})}handleRunButtonClick(){this.setOutputText("Waiting for remote server\u2026"),fetch(p("/play/compile"),{method:"POST",body:JSON.stringify({body:this.getCodeWithModFile(),version:2})}).then(e=>e.json()).then(async({Events:e,Errors:t})=>{this.setOutputText(t||"");for(let i of e||[])this.appendToOutputText(i.Message),await new Promise(s=>setTimeout(s,i.Delay/1e6))}).catch(e=>{this.setErrorText(e)})}};function C(){let l=location.hash.match(/^#(example-.*)$/);if(l){let i=document.getElementById(l[1]);i&&(i.open=!0)}let e=[...document.querySelectorAll(u.PLAY_HREF)],t=i=>e.find(s=>s.hash===i.getAnchorHash());for(let i of document.querySelectorAll(u.PLAY_CONTAINER)){let s=new x(i),n=t(s);n?n.addEventListener("click",()=>{s.expand()}):console.warn("example href not found")}}var f=class{constructor(e){this.el=e;this.el.addEventListener("change",t=>{let i=t.target,s=i.value;i.value.startsWith("/")||(s="/"+s),window.location.href=s})}};function I(l){let e=document.createElement("label");e.classList.add("go-Label"),e.setAttribute("aria-label","Menu");let t=document.createElement("select");t.classList.add("go-Select","js-selectNav"),e.appendChild(t);let i=document.createElement("optgroup");i.label="Outline",t.appendChild(i);let s={},n;for(let r of l.treeitems){if(Number(r.depth)>4)continue;r.groupTreeitem?(n=s[r.groupTreeitem.label],n||(n=s[r.groupTreeitem.label]=document.createElement("optgroup"),n.label=r.groupTreeitem.label,t.appendChild(n))):n=i;let a=document.createElement("option");a.label=r.label,a.textContent=r.label,a.value=r.el.href.replace(window.location.origin,"").replace("/",""),n.appendChild(a)}return l.addObserver(r=>{var h;let a=r.el.hash,d=(h=t.querySelector(`[value$="${a}"]`))==null?void 0:h.value;d&&(t.value=d)},50),e}var E=class{constructor(e){this.el=e;this.handleResize=()=>{this.el.style.setProperty("--js-tree-height","100vh"),this.el.style.setProperty("--js-tree-height",this.el.clientHeight+"px")};this.treeitems=[],this.firstChars=[],this.firstTreeitem=null,this.lastTreeitem=null,this.observerCallbacks=[],this.init()}init(){this.handleResize(),window.addEventListener("resize",this.handleResize),this.findTreeItems(),this.updateVisibleTreeitems(),this.observeTargets(),this.firstTreeitem&&(this.firstTreeitem.el.tabIndex=0)}observeTargets(){this.addObserver(i=>{this.expandTreeitem(i),this.setSelected(i)});let e=new Map,t=new IntersectionObserver(i=>{for(let s of i)e.set(s.target.id,s.isIntersecting||s.intersectionRatio===1);for(let[s,n]of e)if(n){let r=this.treeitems.find(a=>{var d;return(d=a.el)==null?void 0:d.href.endsWith(`#${s}`)});if(r)for(let a of this.observerCallbacks)a(r);break}},{threshold:1,rootMargin:"-60px 0px 0px 0px"});for(let i of this.treeitems.map(s=>s.el.getAttribute("href")))if(i){let s=i.replace(window.location.origin,"").replace("/","").replace("#",""),n=document.getElementById(s);n&&!s.startsWith("example-")&&t.observe(n)}}addObserver(e,t=200){this.observerCallbacks.push(O(e,t))}setFocusToNextItem(e){let t=null;for(let i=e.index+1;i-1;i--){let s=this.treeitems[i];if(s.isVisible){t=s;break}}t&&this.setFocusToItem(t)}setFocusToParentItem(e){e.groupTreeitem&&this.setFocusToItem(e.groupTreeitem)}setFocusToFirstItem(){this.firstTreeitem&&this.setFocusToItem(this.firstTreeitem)}setFocusToLastItem(){this.lastTreeitem&&this.setFocusToItem(this.lastTreeitem)}setSelected(e){var t;for(let i of this.el.querySelectorAll('[aria-expanded="true"]'))i!==e.el&&((t=i.nextElementSibling)!=null&&t.contains(e.el)||i.setAttribute("aria-expanded","false"));for(let i of this.el.querySelectorAll("[aria-selected]"))i!==e.el&&i.setAttribute("aria-selected","false");e.el.setAttribute("aria-selected","true"),this.updateVisibleTreeitems(),this.setFocusToItem(e,!1)}expandTreeitem(e){let t=e;for(;t;)t.isExpandable&&t.el.setAttribute("aria-expanded","true"),t=t.groupTreeitem;this.updateVisibleTreeitems()}expandAllSiblingItems(e){for(let t of this.treeitems)t.groupTreeitem===e.groupTreeitem&&t.isExpandable&&this.expandTreeitem(t)}collapseTreeitem(e){let t=null;e.isExpanded()?t=e:t=e.groupTreeitem,t&&(t.el.setAttribute("aria-expanded","false"),this.updateVisibleTreeitems(),this.setFocusToItem(t))}setFocusByFirstCharacter(e,t){let i,s;t=t.toLowerCase(),i=e.index+1,i===this.treeitems.length&&(i=0),s=this.getIndexFirstChars(i,t),s===-1&&(s=this.getIndexFirstChars(0,t)),s>-1&&this.setFocusToItem(this.treeitems[s])}findTreeItems(){let e=(t,i)=>{let s=i,n=t.firstElementChild;for(;n;)(n.tagName==="A"||n.tagName==="SPAN")&&(s=new g(n,this,i),this.treeitems.push(s),this.firstChars.push(s.label.substring(0,1).toLowerCase())),n.firstElementChild&&e(n,s),n=n.nextElementSibling};e(this.el,null),this.treeitems.map((t,i)=>t.index=i)}updateVisibleTreeitems(){this.firstTreeitem=this.treeitems[0];for(let e of this.treeitems){let t=e.groupTreeitem;for(e.isVisible=!0;t&&t.el!==this.el;)t.isExpanded()||(e.isVisible=!1),t=t.groupTreeitem;e.isVisible&&(this.lastTreeitem=e)}}setFocusToItem(e,t=!0){e.el.tabIndex=0,t&&e.el.focus();for(let i of this.treeitems)i!==e&&(i.el.tabIndex=-1)}getIndexFirstChars(e,t){for(let i=e;i{let s=()=>{t=null,l(...i)};t&&clearTimeout(t),t=setTimeout(s,e)}}var T=class{constructor(e,t){this.table=e;this.toggleAll=t;this.expandAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","true")),this.update()};this.collapseAllItems=()=>{this.toggles.map(e=>e.setAttribute("aria-expanded","false")),this.update()};this.update=()=>{this.updateVisibleItems(),setTimeout(()=>this.updateGlobalToggle())};this.rows=Array.from(e.querySelectorAll("[data-aria-controls]")),this.toggles=Array.from(this.table.querySelectorAll("[aria-expanded]")),this.setAttributes(),this.attachEventListeners(),this.update()}setAttributes(){for(let e of["data-aria-controls","data-aria-labelledby","data-id"])this.table.querySelectorAll(`[${e}]`).forEach(t=>{var i;t.setAttribute(e.replace("data-",""),(i=t.getAttribute(e))!=null?i:""),t.removeAttribute(e)})}attachEventListeners(){var e;this.rows.forEach(t=>{t.addEventListener("click",i=>{this.handleToggleClick(i)})}),(e=this.toggleAll)==null||e.addEventListener("click",()=>{this.expandAllItems()}),document.addEventListener("keydown",t=>{(t.ctrlKey||t.metaKey)&&t.key==="f"&&this.expandAllItems()})}handleToggleClick(e){let t=e.currentTarget;t!=null&&t.hasAttribute("aria-expanded")||(t=this.table.querySelector(`button[aria-controls="${t==null?void 0:t.getAttribute("aria-controls")}"]`));let i=(t==null?void 0:t.getAttribute("aria-expanded"))==="true";t==null||t.setAttribute("aria-expanded",i?"false":"true"),e.stopPropagation(),this.update()}updateVisibleItems(){this.rows.map(e=>{var s;let t=(e==null?void 0:e.getAttribute("aria-expanded"))==="true",i=(s=e==null?void 0:e.getAttribute("aria-controls"))==null?void 0:s.trimEnd().split(" ");i==null||i.map(n=>{let r=document.getElementById(`${n}`);t?(r==null||r.classList.add("visible"),r==null||r.classList.remove("hidden")):(r==null||r.classList.add("hidden"),r==null||r.classList.remove("visible"))})})}updateGlobalToggle(){if(!this.toggleAll)return;this.rows.some(t=>t.hasAttribute("aria-expanded"))&&(this.toggleAll.style.display="block"),this.toggles.some(t=>t.getAttribute("aria-expanded")==="false")?(this.toggleAll.innerText="Expand all",this.toggleAll.onclick=this.expandAllItems,this.toggleAll.setAttribute("aria-label","Expand all directories"),this.toggleAll.setAttribute("aria-live","polite")):(this.toggleAll.innerText="Collapse all",this.toggleAll.onclick=this.collapseAllItems,this.toggleAll.setAttribute("aria-label","Collapse all directories"),this.toggleAll.setAttribute("aria-live","polite"))}};C();var m=document.querySelector(".js-expandableTable");if(m){let l=new T(m,document.querySelector(".js-expandAllDirectories"));window.location.search.includes("expand-directories")&&l.expandAllItems();let e=document.querySelector(".js-showInternalDirectories");e&&(document.querySelector(".UnitDirectories-internal")&&(e.style.display="block",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-describedby","showInternal-description")),e.addEventListener("click",()=>{m.classList.contains("UnitDirectories-showInternal")?(m.classList.remove("UnitDirectories-showInternal"),e.innerText="Show internal",e.setAttribute("aria-label","Show Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","showInternal-description")):(m.classList.add("UnitDirectories-showInternal"),e.innerText="Hide internal",e.setAttribute("aria-label","Hide Internal Directories"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-describedby","hideInternal-description"))})),document.querySelector('html[data-local="true"]')&&(e==null||e.click())}var S=document.querySelector(".js-tree");if(S){let l=new E(S),e=I(l),t=document.querySelector(".js-mainNavMobile");t&&t.firstElementChild&&(t==null||t.replaceChild(e,t.firstElementChild)),e.firstElementChild&&new f(e.firstElementChild)}var o=document.querySelector(".js-readme"),v=document.querySelector(".js-readmeContent"),k=document.querySelector(".js-readmeOutline"),b=document.querySelectorAll(".js-readmeExpand"),w=document.querySelector(".js-readmeCollapse"),y=document.querySelector(".DocNavMobile-select");o&&v&&k&&b.length&&w&&(o.clientHeight>320&&(o==null||o.classList.remove("UnitReadme--expanded"),o==null||o.classList.add("UnitReadme--toggle")),window.location.hash.includes("readme")&&c(),y==null||y.addEventListener("change",l=>{l.target.value.startsWith("readme-")&&c()}),b.forEach(l=>l.addEventListener("click",e=>{e.preventDefault(),c(),o.scrollIntoView()})),w.addEventListener("click",l=>{l.preventDefault(),o.classList.remove("UnitReadme--expanded"),b[1]&&b[1].scrollIntoView({block:"center"})}),v.addEventListener("keyup",()=>{c()}),v.addEventListener("click",()=>{c()}),k.addEventListener("click",()=>{c()}),document.addEventListener("keydown",l=>{(l.ctrlKey||l.metaKey)&&l.key==="f"&&c()}));function c(){history.replaceState(null,"",`${location.pathname}${location.search}#section-readme`),o==null||o.classList.add("UnitReadme--expanded")}function M(){var t;if(!location.hash)return;let l=document.getElementById(location.hash.slice(1)),e=(t=l==null?void 0:l.parentElement)==null?void 0:t.parentElement;(e==null?void 0:e.nodeName)==="DETAILS"&&(e.open=!0)}M();window.addEventListener("hashchange",()=>M());document.querySelectorAll(".js-buildContextSelect").forEach(l=>{l.addEventListener("change",e=>{window.location.search=`?GOOS=${e.target.value}`})});(()=>{if(!document.querySelector("h4[data-kind]"))return;let l=r=>{var d;if(r.startsWith("pkg-")||r.startsWith("section-")||r.startsWith("hdr-"))return!1;let a=(d=r.split(".").pop())!=null?d:r;return/^[a-z]/.test(a)};document.querySelectorAll("h4[data-kind][id]").forEach(r=>{if(!l(r.id))return;let a=r.closest(".Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod");a==null||a.classList.add("Documentation-unexported")}),document.querySelectorAll('.Documentation-indexFunction a[href^="#"], .Documentation-indexType a[href^="#"], .Documentation-indexTypeFunctions a[href^="#"], .Documentation-indexTypeMethods a[href^="#"], .go-Tree a[href^="#"]').forEach(r=>{var a;l(r.getAttribute("href").slice(1))&&((a=r.closest("li"))==null||a.classList.add("Documentation-unexported"))});let e=document.createElement("style");e.textContent="body:not(.show-unexported) .Documentation-unexported{display:none}",document.head.appendChild(e);let t=document.querySelector("#pkg-index");if(!t)return;let i=document.createElement("button");i.type="button",i.className="go-Button go-Button--inline",i.style.marginLeft="0.75rem",i.style.fontSize="0.875rem",i.style.verticalAlign="middle";let s="pkgsitex:showUnexported",n=r=>{document.body.classList.toggle("show-unexported",r),i.textContent=r?"Hide unexported":"Show unexported";try{localStorage.setItem(s,r?"1":"0")}catch{}};n(localStorage.getItem(s)==="1"),i.addEventListener("click",()=>n(!document.body.classList.contains("show-unexported"))),t.appendChild(i)})();
/**
* @license
* Copyright 2024 The Go Authors. All rights reserved.
diff --git a/static/frontend/unit/main/main.js.map b/static/frontend/unit/main/main.js.map
index fbe0b88dd..fa66e7f31 100644
--- a/static/frontend/unit/main/main.js.map
+++ b/static/frontend/unit/main/main.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../../shared/base-path/base-path.ts", "../../../shared/playground/playground.ts", "../../../shared/outline/select.ts", "../../../shared/outline/tree.ts", "../../../shared/table/table.ts", "main.ts"],
- "sourcesContent": ["/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/gogodocs \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/gogodocs\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/gogodocs/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/gogodocs/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/*!\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the playground implementation of the documentation\n// page. The playground involves a \"play\" button that allows you to open up\n// a new link to play.golang.org using the example code.\n\n// The CSS is in static/frontend/unit/main/_doc.css\n\nimport { abs } from '../base-path/base-path';\n\n/**\n * CSS classes used by PlaygroundExampleController\n */\nconst PlayExampleClassName = {\n PLAY_HREF: '.js-exampleHref',\n PLAY_CONTAINER: '.js-exampleContainer',\n EXAMPLE_INPUT: '.Documentation-exampleCode',\n EXAMPLE_OUTPUT: '.Documentation-exampleOutput',\n EXAMPLE_OUTPUT_CONTAINER: '.js-exampleOutputContainer',\n EXAMPLE_ERROR: '.Documentation-exampleError',\n PLAY_BUTTON: '.Documentation-examplePlayButton',\n SHARE_BUTTON: '.Documentation-exampleShareButton',\n FORMAT_BUTTON: '.Documentation-exampleFormatButton',\n RUN_BUTTON: '.Documentation-exampleRunButton',\n};\n\n/**\n * This controller enables playground examples to expand their dropdown or\n * generate shareable Go Playground URLs.\n */\nexport class PlaygroundExampleController {\n /**\n * The anchor tag used to identify the container with an example href.\n * There is only one in an example container div.\n */\n private readonly anchorEl: HTMLAnchorElement | null;\n\n /**\n * The error element\n */\n private readonly errorEl: Element | null;\n\n /**\n * Buttons that redirect to an example's playground, this element\n * only exists in executable examples.\n */\n private readonly playButtonEl: Element | null;\n private readonly shareButtonEl: Element | null;\n\n /**\n * Button that formats the code in an example's playground.\n */\n private readonly formatButtonEl: Element | null;\n\n /**\n * Button that runs the code in an example's playground, this element\n * only exists in executable examples.\n */\n private readonly runButtonEl: Element | null;\n\n /**\n * The executable code of an example.\n */\n private readonly inputEl: HTMLTextAreaElement | null;\n\n /**\n * The output of the given example code. This only exists if the\n * author of the package provides an output for this example.\n */\n private readonly outputEl: Element | null;\n\n /**\n * The container for the output.\n */\n private readonly outputContainerEl: HTMLElement | null;\n\n /**\n * @param exampleEl The div that contains playground content for the given example.\n */\n constructor(private readonly exampleEl: HTMLDetailsElement) {\n this.exampleEl = exampleEl;\n this.anchorEl = exampleEl.querySelector('a');\n this.errorEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_ERROR);\n this.playButtonEl = exampleEl.querySelector(PlayExampleClassName.PLAY_BUTTON);\n this.shareButtonEl = exampleEl.querySelector(PlayExampleClassName.SHARE_BUTTON);\n this.formatButtonEl = exampleEl.querySelector(PlayExampleClassName.FORMAT_BUTTON);\n this.runButtonEl = exampleEl.querySelector(PlayExampleClassName.RUN_BUTTON);\n this.inputEl = this.makeTextArea(exampleEl.querySelector(PlayExampleClassName.EXAMPLE_INPUT));\n this.outputEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT);\n this.outputContainerEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT_CONTAINER);\n\n // This is legacy listener to be replaced the listener for shareButtonEl.\n this.playButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.shareButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.formatButtonEl?.addEventListener('click', () => this.handleFormatButtonClick());\n this.runButtonEl?.addEventListener('click', () => this.handleRunButtonClick());\n\n if (!this.inputEl) return;\n\n this.resize();\n this.inputEl.addEventListener('keyup', () => this.resize());\n this.inputEl.addEventListener('keydown', e => this.onKeydown(e));\n }\n\n /**\n * Replace the pre element with a textarea. The examples are initially rendered\n * as pre elements so they're fully visible when JS is disabled.\n */\n makeTextArea(el: Element | null): HTMLTextAreaElement {\n const t = document.createElement('textarea');\n t.classList.add('Documentation-exampleCode', 'code');\n t.spellcheck = false;\n t.value = el?.textContent ?? '';\n el?.parentElement?.replaceChild(t, el);\n return t;\n }\n\n /**\n * Retrieve the hash value of the anchor element.\n */\n getAnchorHash(): string | undefined {\n return this.anchorEl?.hash;\n }\n\n /**\n * Expands the current playground example.\n */\n expand(): void {\n this.exampleEl.open = true;\n }\n\n /**\n * Resizes the input element to accommodate the amount of text present.\n */\n private resize(): void {\n if (this.inputEl?.value) {\n const numLineBreaks = (this.inputEl.value.match(/\\n/g) || []).length;\n // min-height + lines x line-height + padding + border\n this.inputEl.style.height = `${(20 + numLineBreaks * 20 + 12 + 2) / 16}rem`;\n }\n }\n\n /**\n * Handler to override keyboard behavior in the playground's\n * textarea element.\n *\n * Tab key inserts tabs into the example playground instead of\n * switching to the next interactive element.\n * @param e input element keyboard event.\n */\n private onKeydown(e: KeyboardEvent) {\n if (e.key === 'Tab') {\n document.execCommand('insertText', false, '\\t');\n e.preventDefault();\n }\n }\n\n /**\n * Changes the text of the example's input box.\n */\n private setInputText(output: string) {\n if (this.inputEl) {\n this.inputEl.value = output;\n }\n }\n\n /**\n * Changes the text of the example's output box.\n */\n private setOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent = output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n /**\n * Appends to the text of the example's output box.\n */\n private appendToOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent += output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n private setOutputHTML(output: string) {\n if (this.outputEl) {\n this.outputEl.innerHTML = output;\n }\n }\n\n /**\n * Sets the error message text and overwrites\n * output box to indicate a failed response.\n */\n private setErrorText(err: string) {\n if (this.errorEl) {\n this.errorEl.textContent = err;\n }\n this.setOutputText('An error has occurred\u2026');\n }\n\n private getCodeWithModFile(): string {\n let codeWithModFile = this.inputEl?.value ?? '';\n const moduleVars = document.querySelector('.js-playgroundVars')?.dataset ?? {};\n if (moduleVars.modulepath !== 'std') {\n codeWithModFile = codeWithModFile.concat(`\n-- go.mod --\nmodule play.ground\n\nrequire ${moduleVars.modulepath} ${moduleVars.version}\n`);\n }\n\n return codeWithModFile;\n }\n\n /**\n * Opens a new window to play.golang.org using the\n * example snippet's code in the playground.\n */\n private handleShareButtonClick() {\n const PLAYGROUND_BASE_URL = 'https://play.golang.org/p/';\n\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/share'), {\n method: 'POST',\n body: this.getCodeWithModFile(),\n })\n .then(res => res.text())\n .then(shareId => {\n const href = PLAYGROUND_BASE_URL + shareId;\n this.setOutputHTML(`${href} `);\n window.open(href);\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs gofmt on the example snippet in the playground.\n */\n private handleFormatButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n const body = new FormData();\n body.append('body', this.inputEl?.value ?? '');\n\n fetch(abs('/play/fmt'), {\n method: 'POST',\n body: body,\n })\n .then(res => res.json())\n .then(({ Body, Error }) => {\n this.setOutputText(Error || 'Done.');\n if (Body) {\n this.setInputText(Body);\n this.resize();\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs the code snippet in the example playground.\n */\n private handleRunButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/compile'), {\n method: 'POST',\n body: JSON.stringify({ body: this.getCodeWithModFile(), version: 2 }),\n })\n .then(res => res.json())\n .then(async ({ Events, Errors }) => {\n this.setOutputText(Errors || '');\n for (const e of Events || []) {\n this.appendToOutputText(e.Message);\n await new Promise(resolve => setTimeout(resolve, e.Delay / 1000000));\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n}\n\nexport function initPlaygrounds(): void {\n const exampleHashRegex = location.hash.match(/^#(example-.*)$/);\n if (exampleHashRegex) {\n const exampleHashEl = document.getElementById(exampleHashRegex[1]) as HTMLDetailsElement;\n if (exampleHashEl) {\n exampleHashEl.open = true;\n }\n }\n\n // We use a spread operator to convert a nodelist into an array of elements.\n const exampleHrefs = [\n ...document.querySelectorAll(PlayExampleClassName.PLAY_HREF),\n ];\n\n /**\n * Sometimes exampleHrefs and playContainers are in different order, so we\n * find an exampleHref from a common hash.\n * @param playContainer - playground container\n */\n const findExampleHash = (playContainer: PlaygroundExampleController) =>\n exampleHrefs.find(ex => {\n return ex.hash === playContainer.getAnchorHash();\n });\n\n for (const el of document.querySelectorAll(PlayExampleClassName.PLAY_CONTAINER)) {\n // There should be the same amount of hrefs referencing examples as example containers.\n const playContainer = new PlaygroundExampleController(el as HTMLDetailsElement);\n const exampleHref = findExampleHash(playContainer);\n if (exampleHref) {\n exampleHref.addEventListener('click', () => {\n playContainer.expand();\n });\n } else {\n console.warn('example href not found');\n }\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { TreeNavController } from './tree.js';\n\nexport class SelectNavController {\n constructor(private el: Element) {\n this.el.addEventListener('change', e => {\n const target = e.target as HTMLSelectElement;\n let href = target.value;\n if (!target.value.startsWith('/')) {\n href = '/' + href;\n }\n window.location.href = href;\n });\n }\n}\n\nexport function makeSelectNav(tree: TreeNavController): HTMLLabelElement {\n const label = document.createElement('label');\n label.classList.add('go-Label');\n label.setAttribute('aria-label', 'Menu');\n const select = document.createElement('select');\n select.classList.add('go-Select', 'js-selectNav');\n label.appendChild(select);\n const outline = document.createElement('optgroup');\n outline.label = 'Outline';\n select.appendChild(outline);\n const groupMap: Record = {};\n let group: HTMLOptGroupElement;\n for (const t of tree.treeitems) {\n if (Number(t.depth) > 4) continue;\n if (t.groupTreeitem) {\n group = groupMap[t.groupTreeitem.label];\n if (!group) {\n group = groupMap[t.groupTreeitem.label] = document.createElement('optgroup');\n group.label = t.groupTreeitem.label;\n select.appendChild(group);\n }\n } else {\n group = outline;\n }\n const o = document.createElement('option');\n o.label = t.label;\n o.textContent = t.label;\n o.value = (t.el as HTMLAnchorElement).href.replace(window.location.origin, '').replace('/', '');\n group.appendChild(o);\n }\n tree.addObserver(t => {\n const hash = (t.el as HTMLAnchorElement).hash;\n const value = select.querySelector(`[value$=\"${hash}\"]`)?.value;\n if (value) {\n select.value = value;\n }\n }, 50);\n return label;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * TreeNavController is the navigation tree component of the documentation page.\n * It adds accessiblity attributes to a tree, observes the heading elements\n * focus the topmost link for headings visible on the page, and implements the\n * WAI-ARIA Treeview Design Pattern with full\n * [keyboard support](https://www.w3.org/TR/wai-aria-practices/examples/treeview/treeview-2/treeview-2a.html#kbd_label).\n */\nexport class TreeNavController {\n treeitems: TreeItem[];\n\n /**\n * firstChars is the first character of each treeitem in the same order\n * as this.treeitems. We use this array to set focus by character when\n * navigating the tree with a keyboard.\n */\n private firstChars: string[];\n private firstTreeitem: TreeItem | null;\n private lastTreeitem: TreeItem | null;\n private observerCallbacks: ((t: TreeItem) => void)[];\n\n constructor(private el: HTMLElement) {\n this.treeitems = [];\n this.firstChars = [];\n this.firstTreeitem = null;\n this.lastTreeitem = null;\n this.observerCallbacks = [];\n this.init();\n }\n\n private init(): void {\n this.handleResize();\n window.addEventListener('resize', this.handleResize);\n this.findTreeItems();\n this.updateVisibleTreeitems();\n this.observeTargets();\n if (this.firstTreeitem) {\n this.firstTreeitem.el.tabIndex = 0;\n }\n }\n\n private handleResize = (): void => {\n this.el.style.setProperty('--js-tree-height', '100vh');\n this.el.style.setProperty('--js-tree-height', this.el.clientHeight + 'px');\n };\n\n private observeTargets() {\n this.addObserver(treeitem => {\n this.expandTreeitem(treeitem);\n this.setSelected(treeitem);\n // TODO: Fix scroll issue in https://golang.org/issue/47450.\n // treeitem.el.scrollIntoView({ block: 'nearest' });\n });\n\n const targets = new Map();\n const observer = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n targets.set(entry.target.id, entry.isIntersecting || entry.intersectionRatio === 1);\n }\n for (const [id, isIntersecting] of targets) {\n if (isIntersecting) {\n const active = this.treeitems.find(t =>\n (t.el as HTMLAnchorElement)?.href.endsWith(`#${id}`)\n );\n if (active) {\n for (const fn of this.observerCallbacks) {\n fn(active);\n }\n }\n break;\n }\n }\n },\n {\n threshold: 1.0,\n rootMargin: '-60px 0px 0px 0px',\n }\n );\n\n for (const href of this.treeitems.map(t => t.el.getAttribute('href'))) {\n if (href) {\n const id = href.replace(window.location.origin, '').replace('/', '').replace('#', '');\n const target = document.getElementById(id);\n if (target && !id.startsWith('example-')) {\n observer.observe(target);\n }\n }\n }\n }\n\n addObserver(fn: (t: TreeItem) => void, delay = 200): void {\n this.observerCallbacks.push(debounce(fn, delay));\n }\n\n setFocusToNextItem(currentItem: TreeItem): void {\n let nextItem = null;\n for (let i = currentItem.index + 1; i < this.treeitems.length; i++) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n nextItem = ti;\n break;\n }\n }\n if (nextItem) {\n this.setFocusToItem(nextItem);\n }\n }\n\n setFocusToPreviousItem(currentItem: TreeItem): void {\n let prevItem = null;\n for (let i = currentItem.index - 1; i > -1; i--) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n prevItem = ti;\n break;\n }\n }\n if (prevItem) {\n this.setFocusToItem(prevItem);\n }\n }\n\n setFocusToParentItem(currentItem: TreeItem): void {\n if (currentItem.groupTreeitem) {\n this.setFocusToItem(currentItem.groupTreeitem);\n }\n }\n\n setFocusToFirstItem(): void {\n this.firstTreeitem && this.setFocusToItem(this.firstTreeitem);\n }\n\n setFocusToLastItem(): void {\n this.lastTreeitem && this.setFocusToItem(this.lastTreeitem);\n }\n\n setSelected(currentItem: TreeItem): void {\n for (const l1 of this.el.querySelectorAll('[aria-expanded=\"true\"]')) {\n if (l1 === currentItem.el) continue;\n if (!l1.nextElementSibling?.contains(currentItem.el)) {\n l1.setAttribute('aria-expanded', 'false');\n }\n }\n for (const l1 of this.el.querySelectorAll('[aria-selected]')) {\n if (l1 !== currentItem.el) {\n l1.setAttribute('aria-selected', 'false');\n }\n }\n currentItem.el.setAttribute('aria-selected', 'true');\n this.updateVisibleTreeitems();\n this.setFocusToItem(currentItem, false);\n }\n\n expandTreeitem(treeitem: TreeItem): void {\n let currentItem: TreeItem | null = treeitem;\n while (currentItem) {\n if (currentItem.isExpandable) {\n currentItem.el.setAttribute('aria-expanded', 'true');\n }\n currentItem = currentItem.groupTreeitem;\n }\n this.updateVisibleTreeitems();\n }\n\n expandAllSiblingItems(currentItem: TreeItem): void {\n for (const ti of this.treeitems) {\n if (ti.groupTreeitem === currentItem.groupTreeitem && ti.isExpandable) {\n this.expandTreeitem(ti);\n }\n }\n }\n\n collapseTreeitem(currentItem: TreeItem): void {\n let groupTreeitem = null;\n\n if (currentItem.isExpanded()) {\n groupTreeitem = currentItem;\n } else {\n groupTreeitem = currentItem.groupTreeitem;\n }\n\n if (groupTreeitem) {\n groupTreeitem.el.setAttribute('aria-expanded', 'false');\n this.updateVisibleTreeitems();\n this.setFocusToItem(groupTreeitem);\n }\n }\n\n setFocusByFirstCharacter(currentItem: TreeItem, char: string): void {\n let start: number, index: number;\n char = char.toLowerCase();\n\n // Get start index for search based on position of currentItem\n start = currentItem.index + 1;\n if (start === this.treeitems.length) {\n start = 0;\n }\n\n // Check remaining slots in the menu\n index = this.getIndexFirstChars(start, char);\n\n // If not found in remaining slots, check from beginning\n if (index === -1) {\n index = this.getIndexFirstChars(0, char);\n }\n\n // If match was found...\n if (index > -1) {\n this.setFocusToItem(this.treeitems[index]);\n }\n }\n\n private findTreeItems() {\n const findItems = (el: HTMLElement, group: TreeItem | null) => {\n let ti = group;\n let curr = el.firstElementChild as HTMLElement;\n while (curr) {\n if (curr.tagName === 'A' || curr.tagName === 'SPAN') {\n ti = new TreeItem(curr, this, group);\n this.treeitems.push(ti);\n this.firstChars.push(ti.label.substring(0, 1).toLowerCase());\n }\n if (curr.firstElementChild) {\n findItems(curr, ti);\n }\n curr = curr.nextElementSibling as HTMLElement;\n }\n };\n findItems(this.el as HTMLElement, null);\n this.treeitems.map((ti, idx) => (ti.index = idx));\n }\n\n private updateVisibleTreeitems(): void {\n this.firstTreeitem = this.treeitems[0];\n\n for (const ti of this.treeitems) {\n let parent = ti.groupTreeitem;\n ti.isVisible = true;\n while (parent && parent.el !== this.el) {\n if (!parent.isExpanded()) {\n ti.isVisible = false;\n }\n parent = parent.groupTreeitem;\n }\n if (ti.isVisible) {\n this.lastTreeitem = ti;\n }\n }\n }\n\n private setFocusToItem(treeitem: TreeItem, focusEl = true) {\n treeitem.el.tabIndex = 0;\n if (focusEl) {\n treeitem.el.focus();\n }\n for (const ti of this.treeitems) {\n if (ti !== treeitem) {\n ti.el.tabIndex = -1;\n }\n }\n }\n\n private getIndexFirstChars(startIndex: number, char: string): number {\n for (let i = startIndex; i < this.firstChars.length; i++) {\n if (this.treeitems[i].isVisible && char === this.firstChars[i]) {\n return i;\n }\n }\n return -1;\n }\n}\n\nclass TreeItem {\n el: HTMLElement;\n groupTreeitem: TreeItem | null;\n label: string;\n isExpandable: boolean;\n isVisible: boolean;\n depth: number;\n index: number;\n\n private tree: TreeNavController;\n private isInGroup: boolean;\n\n constructor(el: HTMLElement, treeObj: TreeNavController, group: TreeItem | null) {\n el.tabIndex = -1;\n this.el = el;\n this.groupTreeitem = group;\n this.label = el.textContent?.trim() ?? '';\n this.tree = treeObj;\n this.depth = (group?.depth || 0) + 1;\n this.index = 0;\n\n const parent = el.parentElement;\n if (parent?.tagName.toLowerCase() === 'li') {\n parent?.setAttribute('role', 'none');\n }\n el.setAttribute('aria-level', this.depth + '');\n if (el.getAttribute('aria-label')) {\n this.label = el?.getAttribute('aria-label')?.trim() ?? '';\n }\n\n this.isExpandable = false;\n this.isVisible = false;\n this.isInGroup = !!group;\n\n let curr = el.nextElementSibling;\n while (curr) {\n if (curr.tagName.toLowerCase() == 'ul') {\n const groupId = `${group?.label ?? ''} nav group ${this.label}`.replace(/[\\W_]+/g, '_');\n el.setAttribute('aria-owns', groupId);\n el.setAttribute('aria-expanded', 'false');\n curr.setAttribute('role', 'group');\n curr.setAttribute('id', groupId);\n this.isExpandable = true;\n break;\n }\n\n curr = curr.nextElementSibling;\n }\n this.init();\n }\n\n private init() {\n this.el.tabIndex = -1;\n if (!this.el.getAttribute('role')) {\n this.el.setAttribute('role', 'treeitem');\n }\n this.el.addEventListener('keydown', this.handleKeydown.bind(this));\n this.el.addEventListener('click', this.handleClick.bind(this));\n this.el.addEventListener('focus', this.handleFocus.bind(this));\n this.el.addEventListener('blur', this.handleBlur.bind(this));\n }\n\n isExpanded() {\n if (this.isExpandable) {\n return this.el.getAttribute('aria-expanded') === 'true';\n }\n\n return false;\n }\n\n isSelected() {\n return this.el.getAttribute('aria-selected') === 'true';\n }\n\n private handleClick(event: MouseEvent) {\n // only process click events that directly happened on this treeitem\n if (event.target !== this.el && event.target !== this.el.firstElementChild) {\n return;\n }\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n }\n\n private handleFocus() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.add('focus');\n }\n\n private handleBlur() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.remove('focus');\n }\n\n private handleKeydown(event: KeyboardEvent) {\n if (event.altKey || event.ctrlKey || event.metaKey) {\n return;\n }\n\n let captured = false;\n switch (event.key) {\n case ' ':\n case 'Enter':\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n captured = true;\n } else {\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n break;\n\n case 'ArrowUp':\n this.tree.setFocusToPreviousItem(this);\n captured = true;\n break;\n\n case 'ArrowDown':\n this.tree.setFocusToNextItem(this);\n captured = true;\n break;\n\n case 'ArrowRight':\n if (this.isExpandable) {\n if (this.isExpanded()) {\n this.tree.setFocusToNextItem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n }\n captured = true;\n break;\n\n case 'ArrowLeft':\n if (this.isExpandable && this.isExpanded()) {\n this.tree.collapseTreeitem(this);\n captured = true;\n } else {\n if (this.isInGroup) {\n this.tree.setFocusToParentItem(this);\n captured = true;\n }\n }\n break;\n\n case 'Home':\n this.tree.setFocusToFirstItem();\n captured = true;\n break;\n\n case 'End':\n this.tree.setFocusToLastItem();\n captured = true;\n break;\n\n default:\n if (event.key.length === 1 && event.key.match(/\\S/)) {\n if (event.key == '*') {\n this.tree.expandAllSiblingItems(this);\n } else {\n this.tree.setFocusByFirstCharacter(this, event.key);\n }\n captured = true;\n }\n break;\n }\n\n if (captured) {\n event.stopPropagation();\n event.preventDefault();\n }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction debounce any>(func: T, wait: number) {\n let timeout: ReturnType | null;\n return (...args: Parameters) => {\n const later = () => {\n timeout = null;\n func(...args);\n };\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(later, wait);\n };\n}\n", "/*!\n * @license\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * Controller for a table element with expandable rows. Adds event listeners to\n * a toggle within a table row that controls visiblity of additional related\n * rows in the table.\n *\n * @example\n * ```typescript\n * import {ExpandableRowsTableController} from '/static/js/table';\n *\n * const el = document .querySelector('.js-myTableElement')\n * new ExpandableRowsTableController(el));\n * ```\n */\nexport class ExpandableRowsTableController {\n private rows: HTMLTableRowElement[];\n private toggles: HTMLButtonElement[];\n\n /**\n * Create a table controller.\n * @param table - The table element to which the controller binds.\n */\n constructor(private table: HTMLTableElement, private toggleAll?: HTMLButtonElement | null) {\n this.rows = Array.from(table.querySelectorAll('[data-aria-controls]'));\n this.toggles = Array.from(this.table.querySelectorAll('[aria-expanded]'));\n this.setAttributes();\n this.attachEventListeners();\n this.update();\n }\n\n /**\n * setAttributes sets data-aria-* and data-id attributes to regular\n * html attributes as a workaround for limitations from safehtml.\n */\n private setAttributes() {\n for (const a of ['data-aria-controls', 'data-aria-labelledby', 'data-id']) {\n this.table.querySelectorAll(`[${a}]`).forEach(t => {\n t.setAttribute(a.replace('data-', ''), t.getAttribute(a) ?? '');\n t.removeAttribute(a);\n });\n }\n }\n\n private attachEventListeners() {\n this.rows.forEach(t => {\n t.addEventListener('click', e => {\n this.handleToggleClick(e);\n });\n });\n this.toggleAll?.addEventListener('click', () => {\n this.expandAllItems();\n });\n\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n this.expandAllItems();\n }\n });\n }\n\n private handleToggleClick(e: MouseEvent) {\n let target = e.currentTarget as HTMLTableRowElement | null;\n if (!target?.hasAttribute('aria-expanded')) {\n target = this.table.querySelector(\n `button[aria-controls=\"${target?.getAttribute('aria-controls')}\"]`\n );\n }\n const isExpanded = target?.getAttribute('aria-expanded') === 'true';\n target?.setAttribute('aria-expanded', isExpanded ? 'false' : 'true');\n e.stopPropagation();\n this.update();\n }\n\n expandAllItems = (): void => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'true'));\n this.update();\n };\n\n private collapseAllItems = () => {\n this.toggles.map(t => t.setAttribute('aria-expanded', 'false'));\n this.update();\n };\n\n private update = () => {\n this.updateVisibleItems();\n setTimeout(() => this.updateGlobalToggle());\n };\n\n private updateVisibleItems() {\n this.rows.map(t => {\n const isExpanded = t?.getAttribute('aria-expanded') === 'true';\n const rowIds = t?.getAttribute('aria-controls')?.trimEnd().split(' ');\n rowIds?.map(id => {\n const target = document.getElementById(`${id}`);\n if (isExpanded) {\n target?.classList.add('visible');\n target?.classList.remove('hidden');\n } else {\n target?.classList.add('hidden');\n target?.classList.remove('visible');\n }\n });\n });\n }\n\n private updateGlobalToggle() {\n if (!this.toggleAll) return;\n if (this.rows.some(t => t.hasAttribute('aria-expanded'))) {\n this.toggleAll.style.display = 'block';\n }\n const someCollapsed = this.toggles.some(el => el.getAttribute('aria-expanded') === 'false');\n if (someCollapsed) {\n this.toggleAll.innerText = 'Expand all';\n this.toggleAll.onclick = this.expandAllItems;\n this.toggleAll.setAttribute('aria-label', 'Expand all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n } else {\n this.toggleAll.innerText = 'Collapse all';\n this.toggleAll.onclick = this.collapseAllItems;\n this.toggleAll.setAttribute('aria-label', 'Collapse all directories');\n this.toggleAll.setAttribute('aria-live', 'polite');\n }\n }\n}\n", "import { initPlaygrounds } from 'static/shared/playground/playground';\nimport { SelectNavController, makeSelectNav } from 'static/shared/outline/select';\nimport { TreeNavController } from 'static/shared/outline/tree';\nimport { ExpandableRowsTableController } from 'static/shared/table/table';\n\ninitPlaygrounds();\n\nconst directories = document.querySelector('.js-expandableTable');\nif (directories) {\n const table = new ExpandableRowsTableController(\n directories,\n document.querySelector('.js-expandAllDirectories')\n );\n // Expand directories on page load with expand-directories query param.\n if (window.location.search.includes('expand-directories')) {\n table.expandAllItems();\n }\n\n const internalToggle = document.querySelector('.js-showInternalDirectories');\n if (internalToggle) {\n if (document.querySelector('.UnitDirectories-internal')) {\n internalToggle.style.display = 'block';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n }\n internalToggle.addEventListener('click', () => {\n if (directories.classList.contains('UnitDirectories-showInternal')) {\n directories.classList.remove('UnitDirectories-showInternal');\n internalToggle.innerText = 'Show internal';\n internalToggle.setAttribute('aria-label', 'Show Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'showInternal-description');\n } else {\n directories.classList.add('UnitDirectories-showInternal');\n internalToggle.innerText = 'Hide internal';\n internalToggle.setAttribute('aria-label', 'Hide Internal Directories');\n internalToggle.setAttribute('aria-live', 'polite');\n internalToggle.setAttribute('aria-describedby', 'hideInternal-description');\n }\n });\n }\n if (document.querySelector('html[data-local=\"true\"]')) {\n internalToggle?.click();\n }\n}\n\nconst treeEl = document.querySelector('.js-tree');\nif (treeEl) {\n const treeCtrl = new TreeNavController(treeEl);\n const select = makeSelectNav(treeCtrl);\n const mobileNav = document.querySelector('.js-mainNavMobile');\n if (mobileNav && mobileNav.firstElementChild) {\n mobileNav?.replaceChild(select, mobileNav.firstElementChild);\n }\n if (select.firstElementChild) {\n new SelectNavController(select.firstElementChild);\n }\n}\n\n/**\n * Event handlers for expanding and collapsing the readme section.\n */\nconst readme = document.querySelector('.js-readme');\nconst readmeContent = document.querySelector('.js-readmeContent');\nconst readmeOutline = document.querySelector('.js-readmeOutline');\nconst readmeExpand = document.querySelectorAll('.js-readmeExpand');\nconst readmeCollapse = document.querySelector('.js-readmeCollapse');\nconst mobileNavSelect = document.querySelector('.DocNavMobile-select');\nif (readme && readmeContent && readmeOutline && readmeExpand.length && readmeCollapse) {\n if (readme.clientHeight > 320) {\n readme?.classList.remove('UnitReadme--expanded');\n readme?.classList.add('UnitReadme--toggle');\n }\n if (window.location.hash.includes('readme')) {\n expandReadme();\n }\n mobileNavSelect?.addEventListener('change', e => {\n if ((e.target as HTMLSelectElement).value.startsWith('readme-')) {\n expandReadme();\n }\n });\n readmeExpand.forEach(el =>\n el.addEventListener('click', e => {\n e.preventDefault();\n expandReadme();\n readme.scrollIntoView();\n })\n );\n readmeCollapse.addEventListener('click', e => {\n e.preventDefault();\n readme.classList.remove('UnitReadme--expanded');\n if (readmeExpand[1]) {\n readmeExpand[1].scrollIntoView({ block: 'center' });\n }\n });\n readmeContent.addEventListener('keyup', () => {\n expandReadme();\n });\n readmeContent.addEventListener('click', () => {\n expandReadme();\n });\n readmeOutline.addEventListener('click', () => {\n expandReadme();\n });\n document.addEventListener('keydown', e => {\n if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n expandReadme();\n }\n });\n}\n\n/**\n * expandReadme expands the readme and adds the section-readme hash to the\n * URL so it stays expanded when navigating back from an external link.\n */\nfunction expandReadme() {\n history.replaceState(null, '', `${location.pathname}${location.search}#section-readme`);\n readme?.classList.add('UnitReadme--expanded');\n}\n\n/**\n * Expand details items that are focused. This will expand\n * deprecated symbols when they are navigated to from the index\n * or a direct link.\n */\nfunction openDeprecatedSymbol() {\n if (!location.hash) return;\n const heading = document.getElementById(location.hash.slice(1));\n const grandParent = heading?.parentElement?.parentElement as HTMLDetailsElement | null;\n if (grandParent?.nodeName === 'DETAILS') {\n grandParent.open = true;\n }\n}\nopenDeprecatedSymbol();\nwindow.addEventListener('hashchange', () => openDeprecatedSymbol());\n\n/**\n * Listen for changes in the build context dropdown.\n */\ndocument.querySelectorAll('.js-buildContextSelect').forEach(el => {\n el.addEventListener('change', e => {\n window.location.search = `?GOOS=${(e.target as HTMLSelectElement).value}`;\n });\n});\n\n/**\n * fork\uFF1Aunexported\uFF08\u79C1\u6709\uFF09\u7B26\u53F7 toggle\u3002\n *\n * \u80CC\u666F\uFF1Apkgsite -show-unexported flag \u8BA9 godoc \u628A\u79C1\u6709 type/func/method\n * \u90FD\u6E32\u5230 page\u3002\u4F46\u8BFB\u8005\u5927\u591A\u6570\u65F6\u5019\u53EA\u5173\u5FC3 public API\uFF0C\u79C1\u6709\u7684\u592A\u591A\u53CD\u800C\u62D6\u6162\n * \u9605\u8BFB\u3002\u8FD9\u5C42\u5728 client \u7AEF\u6309 id \u9996\u5B57\u6BCD\u5927\u5C0F\u5199\u81EA\u52A8 hide \u79C1\u6709 declaration +\n * index \u94FE\u63A5\uFF0C\u518D\u6CE8\u5165\u4E00\u4E2A toggle button \u4E00\u952E\u5207\u663E\u793A\u3002\u72B6\u6001\u7528 localStorage\n * \u8BB0\u4E0B\uFF0C\u8DE8\u9875\u4FDD\u7559\u3002\n */\n(() => {\n if (!document.querySelector('h4[data-kind]')) return; // \u975E godoc \u8BE6\u60C5\u9875\n\n // method id \u5F62\u5982 \"Type.method\"\uFF0C\u53D6\u6700\u540E\u6BB5\u5224\u79C1\u6709\uFF1B\u5176\u4ED6\u76F4\u63A5\u5224 id \u672C\u8EAB\u3002\n // \u6392\u9664 pkg-overview / section-readme / pkg-index \u8FD9\u7C7B\u9875\u9762 anchor\u2014\u2014\u5B83\u4EEC\u662F\n // \u5C0F\u5199\u8D77\u5934\u4F46\u4E0D\u662F Go \u7B26\u53F7\uFF0C\u626B\u5230\u4F1A\u8BEF\u6807\u9690\u85CF\u3002\n const isUnexported = (id: string): boolean => {\n if (id.startsWith('pkg-') || id.startsWith('section-') || id.startsWith('hdr-')) {\n return false;\n }\n const last = id.split('.').pop() ?? id;\n return /^[a-z]/.test(last);\n };\n\n // \u6807 declaration wrapper\uFF1Afunc \u5305\u5728 .Documentation-function\uFF1Btype / method\n // \u5305\u5728 .Documentation-type / .Documentation-typeFunc / .Documentation-typeMethod\u3002\n document.querySelectorAll('h4[data-kind][id]').forEach(h => {\n if (!isUnexported(h.id)) return;\n const wrapper = h.closest(\n '.Documentation-function, .Documentation-type, .Documentation-typeFunc, .Documentation-typeMethod'\n );\n wrapper?.classList.add('Documentation-unexported');\n });\n\n // index \u5217\u8868\u9879 + \u5DE6\u4FA7\u8FB9\u680F\uFF08go-Tree outline\uFF09\u6309\u94FE\u63A5\u9996\u5B57\u6BCD\u5224\u3002\n // \u4FA7\u8FB9\u680F\u94FE\u63A5 selector \u76F4\u63A5\u5339\u914D\u6240\u6709 .go-Tree a[href^=\"#\"]\u2014\u2014pkg-overview /\n // section-readme \u7B49\u5BFC\u822A anchor \u5DF2\u88AB isUnexported \u5934\u90E8\u6392\u9664\uFF0C\u4E0D\u4F1A\u8BEF\u6807\u3002\n document\n .querySelectorAll(\n '.Documentation-indexFunction a[href^=\"#\"], ' +\n '.Documentation-indexType a[href^=\"#\"], ' +\n '.Documentation-indexTypeFunctions a[href^=\"#\"], ' +\n '.Documentation-indexTypeMethods a[href^=\"#\"], ' +\n '.go-Tree a[href^=\"#\"]'\n )\n .forEach(a => {\n if (isUnexported(a.getAttribute('href')!.slice(1))) {\n a.closest('li')?.classList.add('Documentation-unexported');\n }\n });\n\n // \u6CE8\u5165 CSS\uFF08\u4E0D\u52A8 main.css build pipeline\uFF0C\u907F\u514D\u589E\u91CF\u6539 esbuild \u8F93\u51FA\uFF09\n const style = document.createElement('style');\n style.textContent =\n 'body:not(.show-unexported) .Documentation-unexported{display:none}';\n document.head.appendChild(style);\n\n // \u6CE8\u5165 toggle button\u2014\u2014\u653E Index \u6807\u9898\u65C1\u8FB9\u6700\u663E\u773C\uFF0C\u8DDF \"Show internal\" \u540C\u4F4D\n const indexHeader = document.querySelector('#pkg-index');\n if (!indexHeader) return;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'go-Button go-Button--inline';\n btn.style.marginLeft = '0.75rem';\n btn.style.fontSize = '0.875rem';\n btn.style.verticalAlign = 'middle';\n\n const STORE_KEY = 'gogodocs:showUnexported';\n const apply = (show: boolean) => {\n document.body.classList.toggle('show-unexported', show);\n btn.textContent = show ? 'Hide unexported' : 'Show unexported';\n try {\n localStorage.setItem(STORE_KEY, show ? '1' : '0');\n } catch {\n /* localStorage \u4E0D\u53EF\u7528\uFF08\u9690\u79C1\u6A21\u5F0F / \u6587\u4EF6\u534F\u8BAE\uFF09\u65F6\u5FFD\u7565\uFF0C\u53EA\u4E22\u5931\u8DE8\u9875\u8BB0\u5FC6 */\n }\n };\n\n apply(localStorage.getItem(STORE_KEY) === '1');\n btn.addEventListener('click', () =>\n apply(!document.body.classList.contains('show-unexported'))\n );\n indexHeader.appendChild(btn);\n})();\n"],
+ "sourcesContent": ["/**\n * @license\n * Copyright 2024 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * \u7AD9\u70B9 URL \u5B50\u8DEF\u5F84\u524D\u7F00\uFF0C\u4ECE \u8BFB\u51FA\u3002\n *\n * fork \u7528 -base-path=/pkgsitex \u542F\u52A8\u65F6\uFF0Cserver \u7AEF\u6A21\u677F\u628A attribute \u5199\u6210\n * \"/pkgsitex\"\uFF1B\u4E0A\u6E38\u516C\u7F51 pkg.go.dev \u9ED8\u8BA4\u6302\u6839\uFF0Cattribute \u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002\n *\n * \u5728 \u4E4B\u5916\u7684\u811A\u672C\u521D\u59CB\u5316\u9636\u6BB5\u8C03\u7528\u90FD\u5B89\u5168\u2014\u2014documentElement \u4E00\u5B9A\u5B58\u5728\u3002\n */\nexport function getBasePath(): string {\n return document.documentElement.dataset.basePath ?? '';\n}\n\n/**\n * \u7ED9\u4EE5 / \u5F00\u5934\u7684\u7EDD\u5BF9\u8DEF\u5F84\u52A0 BasePath \u524D\u7F00\u3002\n *\n * \u7528\u4E8E fetch URL / innerHTML src / location \u6BD4\u8F83\u7B49\u4EFB\u4F55\u9700\u8981\u62FC\u7AD9\u70B9\u7EDD\u5BF9 path\n * \u7684\u5730\u65B9\u3002\u975E\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0D\u4EE5 / \u5F00\u5934\uFF09\u539F\u6837\u8FD4\u56DE\u2014\u2014caller \u81EA\u5DF1\u4FDD\u8BC1\u8BED\u4E49\u3002\n *\n * \u4F8B\uFF1A\n * abs('/play/share') // \u2192 '/pkgsitex/play/share' \u6216 '/play/share'\n * abs('/static/foo.svg') // \u2192 '/pkgsitex/static/foo.svg' \u6216 '/static/foo.svg'\n * abs('relative/x') // \u2192 'relative/x'\uFF08\u4E0D\u52A8\uFF09\n */\nexport function abs(p: string): string {\n if (!p.startsWith('/')) return p;\n return getBasePath() + p;\n}\n", "/*!\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the playground implementation of the documentation\n// page. The playground involves a \"play\" button that allows you to open up\n// a new link to play.golang.org using the example code.\n\n// The CSS is in static/frontend/unit/main/_doc.css\n\nimport { abs } from '../base-path/base-path';\n\n/**\n * CSS classes used by PlaygroundExampleController\n */\nconst PlayExampleClassName = {\n PLAY_HREF: '.js-exampleHref',\n PLAY_CONTAINER: '.js-exampleContainer',\n EXAMPLE_INPUT: '.Documentation-exampleCode',\n EXAMPLE_OUTPUT: '.Documentation-exampleOutput',\n EXAMPLE_OUTPUT_CONTAINER: '.js-exampleOutputContainer',\n EXAMPLE_ERROR: '.Documentation-exampleError',\n PLAY_BUTTON: '.Documentation-examplePlayButton',\n SHARE_BUTTON: '.Documentation-exampleShareButton',\n FORMAT_BUTTON: '.Documentation-exampleFormatButton',\n RUN_BUTTON: '.Documentation-exampleRunButton',\n};\n\n/**\n * This controller enables playground examples to expand their dropdown or\n * generate shareable Go Playground URLs.\n */\nexport class PlaygroundExampleController {\n /**\n * The anchor tag used to identify the container with an example href.\n * There is only one in an example container div.\n */\n private readonly anchorEl: HTMLAnchorElement | null;\n\n /**\n * The error element\n */\n private readonly errorEl: Element | null;\n\n /**\n * Buttons that redirect to an example's playground, this element\n * only exists in executable examples.\n */\n private readonly playButtonEl: Element | null;\n private readonly shareButtonEl: Element | null;\n\n /**\n * Button that formats the code in an example's playground.\n */\n private readonly formatButtonEl: Element | null;\n\n /**\n * Button that runs the code in an example's playground, this element\n * only exists in executable examples.\n */\n private readonly runButtonEl: Element | null;\n\n /**\n * The executable code of an example.\n */\n private readonly inputEl: HTMLTextAreaElement | null;\n\n /**\n * The output of the given example code. This only exists if the\n * author of the package provides an output for this example.\n */\n private readonly outputEl: Element | null;\n\n /**\n * The container for the output.\n */\n private readonly outputContainerEl: HTMLElement | null;\n\n /**\n * @param exampleEl The div that contains playground content for the given example.\n */\n constructor(private readonly exampleEl: HTMLDetailsElement) {\n this.exampleEl = exampleEl;\n this.anchorEl = exampleEl.querySelector('a');\n this.errorEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_ERROR);\n this.playButtonEl = exampleEl.querySelector(PlayExampleClassName.PLAY_BUTTON);\n this.shareButtonEl = exampleEl.querySelector(PlayExampleClassName.SHARE_BUTTON);\n this.formatButtonEl = exampleEl.querySelector(PlayExampleClassName.FORMAT_BUTTON);\n this.runButtonEl = exampleEl.querySelector(PlayExampleClassName.RUN_BUTTON);\n this.inputEl = this.makeTextArea(exampleEl.querySelector(PlayExampleClassName.EXAMPLE_INPUT));\n this.outputEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT);\n this.outputContainerEl = exampleEl.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT_CONTAINER);\n\n // This is legacy listener to be replaced the listener for shareButtonEl.\n this.playButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.shareButtonEl?.addEventListener('click', () => this.handleShareButtonClick());\n this.formatButtonEl?.addEventListener('click', () => this.handleFormatButtonClick());\n this.runButtonEl?.addEventListener('click', () => this.handleRunButtonClick());\n\n if (!this.inputEl) return;\n\n this.resize();\n this.inputEl.addEventListener('keyup', () => this.resize());\n this.inputEl.addEventListener('keydown', e => this.onKeydown(e));\n }\n\n /**\n * Replace the pre element with a textarea. The examples are initially rendered\n * as pre elements so they're fully visible when JS is disabled.\n */\n makeTextArea(el: Element | null): HTMLTextAreaElement {\n const t = document.createElement('textarea');\n t.classList.add('Documentation-exampleCode', 'code');\n t.spellcheck = false;\n t.value = el?.textContent ?? '';\n el?.parentElement?.replaceChild(t, el);\n return t;\n }\n\n /**\n * Retrieve the hash value of the anchor element.\n */\n getAnchorHash(): string | undefined {\n return this.anchorEl?.hash;\n }\n\n /**\n * Expands the current playground example.\n */\n expand(): void {\n this.exampleEl.open = true;\n }\n\n /**\n * Resizes the input element to accommodate the amount of text present.\n */\n private resize(): void {\n if (this.inputEl?.value) {\n const numLineBreaks = (this.inputEl.value.match(/\\n/g) || []).length;\n // min-height + lines x line-height + padding + border\n this.inputEl.style.height = `${(20 + numLineBreaks * 20 + 12 + 2) / 16}rem`;\n }\n }\n\n /**\n * Handler to override keyboard behavior in the playground's\n * textarea element.\n *\n * Tab key inserts tabs into the example playground instead of\n * switching to the next interactive element.\n * @param e input element keyboard event.\n */\n private onKeydown(e: KeyboardEvent) {\n if (e.key === 'Tab') {\n document.execCommand('insertText', false, '\\t');\n e.preventDefault();\n }\n }\n\n /**\n * Changes the text of the example's input box.\n */\n private setInputText(output: string) {\n if (this.inputEl) {\n this.inputEl.value = output;\n }\n }\n\n /**\n * Changes the text of the example's output box.\n */\n private setOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent = output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n /**\n * Appends to the text of the example's output box.\n */\n private appendToOutputText(output: string) {\n if (this.outputEl) {\n this.outputEl.textContent += output;\n }\n if (this.outputContainerEl) {\n this.outputContainerEl.hidden = false;\n }\n }\n\n private setOutputHTML(output: string) {\n if (this.outputEl) {\n this.outputEl.innerHTML = output;\n }\n }\n\n /**\n * Sets the error message text and overwrites\n * output box to indicate a failed response.\n */\n private setErrorText(err: string) {\n if (this.errorEl) {\n this.errorEl.textContent = err;\n }\n this.setOutputText('An error has occurred\u2026');\n }\n\n private getCodeWithModFile(): string {\n let codeWithModFile = this.inputEl?.value ?? '';\n const moduleVars = document.querySelector('.js-playgroundVars')?.dataset ?? {};\n if (moduleVars.modulepath !== 'std') {\n codeWithModFile = codeWithModFile.concat(`\n-- go.mod --\nmodule play.ground\n\nrequire ${moduleVars.modulepath} ${moduleVars.version}\n`);\n }\n\n return codeWithModFile;\n }\n\n /**\n * Opens a new window to play.golang.org using the\n * example snippet's code in the playground.\n */\n private handleShareButtonClick() {\n const PLAYGROUND_BASE_URL = 'https://play.golang.org/p/';\n\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/share'), {\n method: 'POST',\n body: this.getCodeWithModFile(),\n })\n .then(res => res.text())\n .then(shareId => {\n const href = PLAYGROUND_BASE_URL + shareId;\n this.setOutputHTML(`${href} `);\n window.open(href);\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs gofmt on the example snippet in the playground.\n */\n private handleFormatButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n const body = new FormData();\n body.append('body', this.inputEl?.value ?? '');\n\n fetch(abs('/play/fmt'), {\n method: 'POST',\n body: body,\n })\n .then(res => res.json())\n .then(({ Body, Error }) => {\n this.setOutputText(Error || 'Done.');\n if (Body) {\n this.setInputText(Body);\n this.resize();\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n\n /**\n * Runs the code snippet in the example playground.\n */\n private handleRunButtonClick() {\n this.setOutputText('Waiting for remote server\u2026');\n\n fetch(abs('/play/compile'), {\n method: 'POST',\n body: JSON.stringify({ body: this.getCodeWithModFile(), version: 2 }),\n })\n .then(res => res.json())\n .then(async ({ Events, Errors }) => {\n this.setOutputText(Errors || '');\n for (const e of Events || []) {\n this.appendToOutputText(e.Message);\n await new Promise(resolve => setTimeout(resolve, e.Delay / 1000000));\n }\n })\n .catch(err => {\n this.setErrorText(err);\n });\n }\n}\n\nexport function initPlaygrounds(): void {\n const exampleHashRegex = location.hash.match(/^#(example-.*)$/);\n if (exampleHashRegex) {\n const exampleHashEl = document.getElementById(exampleHashRegex[1]) as HTMLDetailsElement;\n if (exampleHashEl) {\n exampleHashEl.open = true;\n }\n }\n\n // We use a spread operator to convert a nodelist into an array of elements.\n const exampleHrefs = [\n ...document.querySelectorAll(PlayExampleClassName.PLAY_HREF),\n ];\n\n /**\n * Sometimes exampleHrefs and playContainers are in different order, so we\n * find an exampleHref from a common hash.\n * @param playContainer - playground container\n */\n const findExampleHash = (playContainer: PlaygroundExampleController) =>\n exampleHrefs.find(ex => {\n return ex.hash === playContainer.getAnchorHash();\n });\n\n for (const el of document.querySelectorAll(PlayExampleClassName.PLAY_CONTAINER)) {\n // There should be the same amount of hrefs referencing examples as example containers.\n const playContainer = new PlaygroundExampleController(el as HTMLDetailsElement);\n const exampleHref = findExampleHash(playContainer);\n if (exampleHref) {\n exampleHref.addEventListener('click', () => {\n playContainer.expand();\n });\n } else {\n console.warn('example href not found');\n }\n }\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { TreeNavController } from './tree.js';\n\nexport class SelectNavController {\n constructor(private el: Element) {\n this.el.addEventListener('change', e => {\n const target = e.target as HTMLSelectElement;\n let href = target.value;\n if (!target.value.startsWith('/')) {\n href = '/' + href;\n }\n window.location.href = href;\n });\n }\n}\n\nexport function makeSelectNav(tree: TreeNavController): HTMLLabelElement {\n const label = document.createElement('label');\n label.classList.add('go-Label');\n label.setAttribute('aria-label', 'Menu');\n const select = document.createElement('select');\n select.classList.add('go-Select', 'js-selectNav');\n label.appendChild(select);\n const outline = document.createElement('optgroup');\n outline.label = 'Outline';\n select.appendChild(outline);\n const groupMap: Record = {};\n let group: HTMLOptGroupElement;\n for (const t of tree.treeitems) {\n if (Number(t.depth) > 4) continue;\n if (t.groupTreeitem) {\n group = groupMap[t.groupTreeitem.label];\n if (!group) {\n group = groupMap[t.groupTreeitem.label] = document.createElement('optgroup');\n group.label = t.groupTreeitem.label;\n select.appendChild(group);\n }\n } else {\n group = outline;\n }\n const o = document.createElement('option');\n o.label = t.label;\n o.textContent = t.label;\n o.value = (t.el as HTMLAnchorElement).href.replace(window.location.origin, '').replace('/', '');\n group.appendChild(o);\n }\n tree.addObserver(t => {\n const hash = (t.el as HTMLAnchorElement).hash;\n const value = select.querySelector(`[value$=\"${hash}\"]`)?.value;\n if (value) {\n select.value = value;\n }\n }, 50);\n return label;\n}\n", "/**\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * TreeNavController is the navigation tree component of the documentation page.\n * It adds accessiblity attributes to a tree, observes the heading elements\n * focus the topmost link for headings visible on the page, and implements the\n * WAI-ARIA Treeview Design Pattern with full\n * [keyboard support](https://www.w3.org/TR/wai-aria-practices/examples/treeview/treeview-2/treeview-2a.html#kbd_label).\n */\nexport class TreeNavController {\n treeitems: TreeItem[];\n\n /**\n * firstChars is the first character of each treeitem in the same order\n * as this.treeitems. We use this array to set focus by character when\n * navigating the tree with a keyboard.\n */\n private firstChars: string[];\n private firstTreeitem: TreeItem | null;\n private lastTreeitem: TreeItem | null;\n private observerCallbacks: ((t: TreeItem) => void)[];\n\n constructor(private el: HTMLElement) {\n this.treeitems = [];\n this.firstChars = [];\n this.firstTreeitem = null;\n this.lastTreeitem = null;\n this.observerCallbacks = [];\n this.init();\n }\n\n private init(): void {\n this.handleResize();\n window.addEventListener('resize', this.handleResize);\n this.findTreeItems();\n this.updateVisibleTreeitems();\n this.observeTargets();\n if (this.firstTreeitem) {\n this.firstTreeitem.el.tabIndex = 0;\n }\n }\n\n private handleResize = (): void => {\n this.el.style.setProperty('--js-tree-height', '100vh');\n this.el.style.setProperty('--js-tree-height', this.el.clientHeight + 'px');\n };\n\n private observeTargets() {\n this.addObserver(treeitem => {\n this.expandTreeitem(treeitem);\n this.setSelected(treeitem);\n // TODO: Fix scroll issue in https://golang.org/issue/47450.\n // treeitem.el.scrollIntoView({ block: 'nearest' });\n });\n\n const targets = new Map();\n const observer = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n targets.set(entry.target.id, entry.isIntersecting || entry.intersectionRatio === 1);\n }\n for (const [id, isIntersecting] of targets) {\n if (isIntersecting) {\n const active = this.treeitems.find(t =>\n (t.el as HTMLAnchorElement)?.href.endsWith(`#${id}`)\n );\n if (active) {\n for (const fn of this.observerCallbacks) {\n fn(active);\n }\n }\n break;\n }\n }\n },\n {\n threshold: 1.0,\n rootMargin: '-60px 0px 0px 0px',\n }\n );\n\n for (const href of this.treeitems.map(t => t.el.getAttribute('href'))) {\n if (href) {\n const id = href.replace(window.location.origin, '').replace('/', '').replace('#', '');\n const target = document.getElementById(id);\n if (target && !id.startsWith('example-')) {\n observer.observe(target);\n }\n }\n }\n }\n\n addObserver(fn: (t: TreeItem) => void, delay = 200): void {\n this.observerCallbacks.push(debounce(fn, delay));\n }\n\n setFocusToNextItem(currentItem: TreeItem): void {\n let nextItem = null;\n for (let i = currentItem.index + 1; i < this.treeitems.length; i++) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n nextItem = ti;\n break;\n }\n }\n if (nextItem) {\n this.setFocusToItem(nextItem);\n }\n }\n\n setFocusToPreviousItem(currentItem: TreeItem): void {\n let prevItem = null;\n for (let i = currentItem.index - 1; i > -1; i--) {\n const ti = this.treeitems[i];\n if (ti.isVisible) {\n prevItem = ti;\n break;\n }\n }\n if (prevItem) {\n this.setFocusToItem(prevItem);\n }\n }\n\n setFocusToParentItem(currentItem: TreeItem): void {\n if (currentItem.groupTreeitem) {\n this.setFocusToItem(currentItem.groupTreeitem);\n }\n }\n\n setFocusToFirstItem(): void {\n this.firstTreeitem && this.setFocusToItem(this.firstTreeitem);\n }\n\n setFocusToLastItem(): void {\n this.lastTreeitem && this.setFocusToItem(this.lastTreeitem);\n }\n\n setSelected(currentItem: TreeItem): void {\n for (const l1 of this.el.querySelectorAll('[aria-expanded=\"true\"]')) {\n if (l1 === currentItem.el) continue;\n if (!l1.nextElementSibling?.contains(currentItem.el)) {\n l1.setAttribute('aria-expanded', 'false');\n }\n }\n for (const l1 of this.el.querySelectorAll('[aria-selected]')) {\n if (l1 !== currentItem.el) {\n l1.setAttribute('aria-selected', 'false');\n }\n }\n currentItem.el.setAttribute('aria-selected', 'true');\n this.updateVisibleTreeitems();\n this.setFocusToItem(currentItem, false);\n }\n\n expandTreeitem(treeitem: TreeItem): void {\n let currentItem: TreeItem | null = treeitem;\n while (currentItem) {\n if (currentItem.isExpandable) {\n currentItem.el.setAttribute('aria-expanded', 'true');\n }\n currentItem = currentItem.groupTreeitem;\n }\n this.updateVisibleTreeitems();\n }\n\n expandAllSiblingItems(currentItem: TreeItem): void {\n for (const ti of this.treeitems) {\n if (ti.groupTreeitem === currentItem.groupTreeitem && ti.isExpandable) {\n this.expandTreeitem(ti);\n }\n }\n }\n\n collapseTreeitem(currentItem: TreeItem): void {\n let groupTreeitem = null;\n\n if (currentItem.isExpanded()) {\n groupTreeitem = currentItem;\n } else {\n groupTreeitem = currentItem.groupTreeitem;\n }\n\n if (groupTreeitem) {\n groupTreeitem.el.setAttribute('aria-expanded', 'false');\n this.updateVisibleTreeitems();\n this.setFocusToItem(groupTreeitem);\n }\n }\n\n setFocusByFirstCharacter(currentItem: TreeItem, char: string): void {\n let start: number, index: number;\n char = char.toLowerCase();\n\n // Get start index for search based on position of currentItem\n start = currentItem.index + 1;\n if (start === this.treeitems.length) {\n start = 0;\n }\n\n // Check remaining slots in the menu\n index = this.getIndexFirstChars(start, char);\n\n // If not found in remaining slots, check from beginning\n if (index === -1) {\n index = this.getIndexFirstChars(0, char);\n }\n\n // If match was found...\n if (index > -1) {\n this.setFocusToItem(this.treeitems[index]);\n }\n }\n\n private findTreeItems() {\n const findItems = (el: HTMLElement, group: TreeItem | null) => {\n let ti = group;\n let curr = el.firstElementChild as HTMLElement;\n while (curr) {\n if (curr.tagName === 'A' || curr.tagName === 'SPAN') {\n ti = new TreeItem(curr, this, group);\n this.treeitems.push(ti);\n this.firstChars.push(ti.label.substring(0, 1).toLowerCase());\n }\n if (curr.firstElementChild) {\n findItems(curr, ti);\n }\n curr = curr.nextElementSibling as HTMLElement;\n }\n };\n findItems(this.el as HTMLElement, null);\n this.treeitems.map((ti, idx) => (ti.index = idx));\n }\n\n private updateVisibleTreeitems(): void {\n this.firstTreeitem = this.treeitems[0];\n\n for (const ti of this.treeitems) {\n let parent = ti.groupTreeitem;\n ti.isVisible = true;\n while (parent && parent.el !== this.el) {\n if (!parent.isExpanded()) {\n ti.isVisible = false;\n }\n parent = parent.groupTreeitem;\n }\n if (ti.isVisible) {\n this.lastTreeitem = ti;\n }\n }\n }\n\n private setFocusToItem(treeitem: TreeItem, focusEl = true) {\n treeitem.el.tabIndex = 0;\n if (focusEl) {\n treeitem.el.focus();\n }\n for (const ti of this.treeitems) {\n if (ti !== treeitem) {\n ti.el.tabIndex = -1;\n }\n }\n }\n\n private getIndexFirstChars(startIndex: number, char: string): number {\n for (let i = startIndex; i < this.firstChars.length; i++) {\n if (this.treeitems[i].isVisible && char === this.firstChars[i]) {\n return i;\n }\n }\n return -1;\n }\n}\n\nclass TreeItem {\n el: HTMLElement;\n groupTreeitem: TreeItem | null;\n label: string;\n isExpandable: boolean;\n isVisible: boolean;\n depth: number;\n index: number;\n\n private tree: TreeNavController;\n private isInGroup: boolean;\n\n constructor(el: HTMLElement, treeObj: TreeNavController, group: TreeItem | null) {\n el.tabIndex = -1;\n this.el = el;\n this.groupTreeitem = group;\n this.label = el.textContent?.trim() ?? '';\n this.tree = treeObj;\n this.depth = (group?.depth || 0) + 1;\n this.index = 0;\n\n const parent = el.parentElement;\n if (parent?.tagName.toLowerCase() === 'li') {\n parent?.setAttribute('role', 'none');\n }\n el.setAttribute('aria-level', this.depth + '');\n if (el.getAttribute('aria-label')) {\n this.label = el?.getAttribute('aria-label')?.trim() ?? '';\n }\n\n this.isExpandable = false;\n this.isVisible = false;\n this.isInGroup = !!group;\n\n let curr = el.nextElementSibling;\n while (curr) {\n if (curr.tagName.toLowerCase() == 'ul') {\n const groupId = `${group?.label ?? ''} nav group ${this.label}`.replace(/[\\W_]+/g, '_');\n el.setAttribute('aria-owns', groupId);\n el.setAttribute('aria-expanded', 'false');\n curr.setAttribute('role', 'group');\n curr.setAttribute('id', groupId);\n this.isExpandable = true;\n break;\n }\n\n curr = curr.nextElementSibling;\n }\n this.init();\n }\n\n private init() {\n this.el.tabIndex = -1;\n if (!this.el.getAttribute('role')) {\n this.el.setAttribute('role', 'treeitem');\n }\n this.el.addEventListener('keydown', this.handleKeydown.bind(this));\n this.el.addEventListener('click', this.handleClick.bind(this));\n this.el.addEventListener('focus', this.handleFocus.bind(this));\n this.el.addEventListener('blur', this.handleBlur.bind(this));\n }\n\n isExpanded() {\n if (this.isExpandable) {\n return this.el.getAttribute('aria-expanded') === 'true';\n }\n\n return false;\n }\n\n isSelected() {\n return this.el.getAttribute('aria-selected') === 'true';\n }\n\n private handleClick(event: MouseEvent) {\n // only process click events that directly happened on this treeitem\n if (event.target !== this.el && event.target !== this.el.firstElementChild) {\n return;\n }\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n }\n\n private handleFocus() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.add('focus');\n }\n\n private handleBlur() {\n let el = this.el;\n if (this.isExpandable) {\n el = (el.firstElementChild as HTMLElement) ?? el;\n }\n el.classList.remove('focus');\n }\n\n private handleKeydown(event: KeyboardEvent) {\n if (event.altKey || event.ctrlKey || event.metaKey) {\n return;\n }\n\n let captured = false;\n switch (event.key) {\n case ' ':\n case 'Enter':\n if (this.isExpandable) {\n if (this.isExpanded() && this.isSelected()) {\n this.tree.collapseTreeitem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n captured = true;\n } else {\n event.stopPropagation();\n }\n this.tree.setSelected(this);\n break;\n\n case 'ArrowUp':\n this.tree.setFocusToPreviousItem(this);\n captured = true;\n break;\n\n case 'ArrowDown':\n this.tree.setFocusToNextItem(this);\n captured = true;\n break;\n\n case 'ArrowRight':\n if (this.isExpandable) {\n if (this.isExpanded()) {\n this.tree.setFocusToNextItem(this);\n } else {\n this.tree.expandTreeitem(this);\n }\n }\n captured = true;\n break;\n\n case 'ArrowLeft':\n if (this.isExpandable && this.isExpanded()) {\n this.tree.collapseTreeitem(this);\n captured = true;\n } else {\n if (this.isInGroup) {\n this.tree.setFocusToParentItem(this);\n captured = true;\n }\n }\n break;\n\n case 'Home':\n this.tree.setFocusToFirstItem();\n captured = true;\n break;\n\n case 'End':\n this.tree.setFocusToLastItem();\n captured = true;\n break;\n\n default:\n if (event.key.length === 1 && event.key.match(/\\S/)) {\n if (event.key == '*') {\n this.tree.expandAllSiblingItems(this);\n } else {\n this.tree.setFocusByFirstCharacter(this, event.key);\n }\n captured = true;\n }\n break;\n }\n\n if (captured) {\n event.stopPropagation();\n event.preventDefault();\n }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction debounce any>(func: T, wait: number) {\n let timeout: ReturnType | null;\n return (...args: Parameters) => {\n const later = () => {\n timeout = null;\n func(...args);\n };\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(later, wait);\n };\n}\n", "/*!\n * @license\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n/**\n * Controller for a table element with expandable rows. Adds event listeners to\n * a toggle within a table row that controls visiblity of additional related\n * rows in the table.\n *\n * @example\n * ```typescript\n * import {ExpandableRowsTableController} from '/static/js/table';\n *\n * const el = document .querySelector('.js-myTableElement')\n * new ExpandableRowsTableController(el));\n * ```\n */\nexport class ExpandableRowsTableController {\n private rows: HTMLTableRowElement[];\n private toggles: HTMLButtonElement[];\n\n /**\n * Create a table controller.\n * @param table - The table element to which the controller binds.\n */\n constructor(private table: HTMLTableElement, private toggleAll?: HTMLButtonElement | null) {\n this.rows = Array.from(table.querySelectorAll