| 1 |
|
| 2 |
(function () { |
| 3 |
"use strict"; |
| 4 |
|
| 5 |
var p = location.pathname, best = null; |
| 6 |
document.querySelectorAll(".band a").forEach(function (a) { |
| 7 |
var h = a.getAttribute("href"); |
| 8 |
if (h !== "/" && (p === h || p.indexOf(h + "/") === 0) && (!best || h.length > best.getAttribute("href").length)) best = a; |
| 9 |
}); |
| 10 |
if (best) best.classList.add("on"); |
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
function load(src, css) { |
| 15 |
return new Promise(function (ok) { |
| 16 |
if (css) { var l = document.createElement("link"); l.rel = "stylesheet"; l.href = css; document.head.appendChild(l); } |
| 17 |
var s = document.createElement("script"); s.src = src; s.onload = ok; document.head.appendChild(s); |
| 18 |
}); |
| 19 |
} |
| 20 |
if (document.querySelector("textarea.code")) load("/static/vendor/editor.js"); |
| 21 |
var mds = document.querySelectorAll("textarea.md"); |
| 22 |
if (mds.length) load("/static/vendor/easymde.min.js", "/static/vendor/easymde.min.css").then(function () { |
| 23 |
var E = window.EasyMDE; |
| 24 |
function b(name, action, text, title) { return { name: name, action: action, text: text, title: title, className: "mde-btn" }; } |
| 25 |
var toolbar = [b("bold", E.toggleBold, "B", "Bold"), b("italic", E.toggleItalic, "I", "Italic"), b("heading", E.toggleHeadingSmaller, "H", "Heading"), "|", |
| 26 |
b("code", E.toggleCodeBlock, "</>", "Code"), b("quote", E.toggleBlockquote, "“", "Quote"), b("ul", E.toggleUnorderedList, "•", "List"), b("ol", E.toggleOrderedList, "1.", "Numbered list"), "|", |
| 27 |
b("link", E.drawLink, "link", "Link"), "|", b("preview", E.togglePreview, "preview", "Preview")]; |
| 28 |
mds.forEach(function (t) { new E({ element: t, spellChecker: false, status: false, forceSync: true, autoDownloadFontAwesome: false, toolbar: toolbar }); }); |
| 29 |
}); |
| 30 |
|
| 31 |
|
| 32 |
var toggle = document.querySelector("[data-theme-toggle]"); |
| 33 |
if (toggle) { |
| 34 |
var root = document.documentElement, order = ["dark", "light", "auto"], glyph = { dark: "◐", light: "☀", auto: "◑" }; |
| 35 |
var show = function () { |
| 36 |
var p = root.dataset.themePref || "dark"; |
| 37 |
toggle.title = "Theme: " + p + " (click to change)"; |
| 38 |
toggle.setAttribute("aria-label", toggle.title); |
| 39 |
toggle.firstElementChild.textContent = glyph[p]; |
| 40 |
}; |
| 41 |
show(); |
| 42 |
toggle.addEventListener("click", function () { |
| 43 |
var p = order[(order.indexOf(root.dataset.themePref || "dark") + 1) % order.length]; |
| 44 |
document.cookie = "theme=" + p + "; path=/; max-age=31536000; samesite=lax"; |
| 45 |
root.dataset.themePref = p; |
| 46 |
root.dataset.theme = p === "auto" ? (window.matchMedia && matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark") : p; |
| 47 |
show(); |
| 48 |
}); |
| 49 |
} |
| 50 |
|
| 51 |
|
| 52 |
var diffs = document.querySelectorAll("table.code.diff"); |
| 53 |
if (diffs.length) { |
| 54 |
var pane = function (tr, col, side) { |
| 55 |
var n = document.createElement("td"), t = document.createElement("td"); |
| 56 |
n.className = "n"; t.className = "t" + (side === "right" ? " mid" : ""); |
| 57 |
if (!tr) { n.className += " none"; t.className += " none"; return [n, t]; } |
| 58 |
var kind = tr.classList.contains("add") ? "add" : tr.classList.contains("del") ? "del" : "ctx"; |
| 59 |
if (kind !== "ctx") { n.className += " " + kind; t.className += " " + kind; } |
| 60 |
n.textContent = tr.cells[col].textContent; |
| 61 |
t.innerHTML = tr.cells[3].innerHTML; |
| 62 |
|
| 63 |
if (side === "left") t.querySelectorAll(".linecomment").forEach(function (d) { d.remove(); }); |
| 64 |
return [n, t]; |
| 65 |
}; |
| 66 |
var split = function (table) { |
| 67 |
var s = document.createElement("table"); |
| 68 |
s.className = "code diff split"; |
| 69 |
s.innerHTML = '<colgroup><col class="n"><col><col class="n"><col></colgroup>'; |
| 70 |
var rows = [].slice.call(table.rows), i = 0; |
| 71 |
var add = function (l, r) { |
| 72 |
var tr = s.insertRow(); |
| 73 |
pane(l, 0, "left").concat(pane(r, 1, "right")).forEach(function (c) { tr.appendChild(c); }); |
| 74 |
}; |
| 75 |
while (i < rows.length) { |
| 76 |
var r = rows[i]; |
| 77 |
if (r.classList.contains("del") || r.classList.contains("add")) { |
| 78 |
var dels = [], adds = []; |
| 79 |
while (i < rows.length && rows[i].classList.contains("del")) dels.push(rows[i++]); |
| 80 |
while (i < rows.length && rows[i].classList.contains("add")) adds.push(rows[i++]); |
| 81 |
for (var k = 0; k < Math.max(dels.length, adds.length); k++) add(dels[k], adds[k]); |
| 82 |
continue; |
| 83 |
} |
| 84 |
if (r.classList.contains("gap") || r.querySelector("td.thread")) { |
| 85 |
var tr = s.insertRow(), td = tr.insertCell(); |
| 86 |
tr.className = r.className; td.colSpan = 4; td.className = r.cells[r.cells.length - 1].className; |
| 87 |
td.innerHTML = r.cells[r.cells.length - 1].innerHTML; |
| 88 |
} else { |
| 89 |
add(r, r); |
| 90 |
} |
| 91 |
i++; |
| 92 |
} |
| 93 |
return s; |
| 94 |
}; |
| 95 |
var cookieMode = (document.cookie.match(/(?:^|; )diff=(split|unified)/) || [])[1] || "unified"; |
| 96 |
var apply = function (mode) { |
| 97 |
diffs.forEach(function (t) { |
| 98 |
if (mode === "split" && !t._split) { t._split = split(t); t.parentNode.insertBefore(t._split, t.nextSibling); } |
| 99 |
t.hidden = mode === "split"; |
| 100 |
if (t._split) t._split.hidden = mode !== "split"; |
| 101 |
}); |
| 102 |
document.querySelectorAll("[data-diff-mode]").forEach(function (a) { a.classList.toggle("on", a.getAttribute("data-diff-mode") === mode); }); |
| 103 |
}; |
| 104 |
document.querySelectorAll("[data-diff-modes], [data-diff-collapse]").forEach(function (e) { e.hidden = false; }); |
| 105 |
document.querySelectorAll("[data-diff-mode]").forEach(function (a) { |
| 106 |
a.addEventListener("click", function (ev) { |
| 107 |
ev.preventDefault(); |
| 108 |
var mode = a.getAttribute("data-diff-mode"); |
| 109 |
document.cookie = "diff=" + mode + "; path=/; max-age=31536000; samesite=lax"; |
| 110 |
apply(mode); |
| 111 |
}); |
| 112 |
}); |
| 113 |
document.querySelectorAll("[data-diff-collapse]").forEach(function (a) { |
| 114 |
a.addEventListener("click", function (ev) { |
| 115 |
ev.preventDefault(); |
| 116 |
var files = document.querySelectorAll("details.file-diff"), anyOpen = [].some.call(files, function (d) { return d.open; }); |
| 117 |
files.forEach(function (d) { d.open = !anyOpen; }); |
| 118 |
a.textContent = anyOpen ? "expand all" : "collapse all"; |
| 119 |
}); |
| 120 |
}); |
| 121 |
apply(cookieMode); |
| 122 |
} |
| 123 |
|
| 124 |
|
| 125 |
var navLinks = document.querySelectorAll(".section-nav a[href^='#']"); |
| 126 |
if (navLinks.length && "IntersectionObserver" in window) { |
| 127 |
var byId = {}; |
| 128 |
navLinks.forEach(function (a) { byId[a.getAttribute("href").slice(1)] = a; }); |
| 129 |
var io = new IntersectionObserver(function (entries) { |
| 130 |
entries.forEach(function (e) { |
| 131 |
if (e.isIntersecting && byId[e.target.id]) { |
| 132 |
navLinks.forEach(function (a) { a.classList.remove("on"); }); |
| 133 |
byId[e.target.id].classList.add("on"); |
| 134 |
} |
| 135 |
}); |
| 136 |
}, { rootMargin: "0px 0px -70% 0px" }); |
| 137 |
Object.keys(byId).forEach(function (id) { var el = document.getElementById(id); if (el) io.observe(el); }); |
| 138 |
} |
| 139 |
|
| 140 |
|
| 141 |
document.querySelectorAll("[data-copy]").forEach(function (b) { |
| 142 |
b.addEventListener("click", function () { |
| 143 |
navigator.clipboard.writeText(b.getAttribute("data-copy")).then(function () { |
| 144 |
var t = b.textContent; b.textContent = "copied"; setTimeout(function () { b.textContent = t; }, 1200); |
| 145 |
}); |
| 146 |
}); |
| 147 |
}); |
| 148 |
|
| 149 |
|
| 150 |
var tree = document.querySelector("table.tree[data-last]"); |
| 151 |
if (tree) { |
| 152 |
var paths = [].map.call(tree.querySelectorAll("tr[data-path]"), function (r) { return r.getAttribute("data-path"); }); |
| 153 |
if (paths.length) { |
| 154 |
fetch(tree.getAttribute("data-last") + "?paths=" + encodeURIComponent(paths.join(",")), { credentials: "same-origin" }) |
| 155 |
.then(function (r) { return r.json(); }) |
| 156 |
.then(function (rows) { |
| 157 |
rows.forEach(function (c) { |
| 158 |
var tr = tree.querySelector('tr[data-path="' + CSS.escape(c.path) + '"]'); |
| 159 |
if (!tr) return; |
| 160 |
var a = tr.querySelector("td.last a"), t = tr.querySelector("td.age"); |
| 161 |
if (a) { a.textContent = c.title; a.href = tree.getAttribute("data-change") + c.hash; } |
| 162 |
if (t) { t.textContent = c.ago; t.title = c.when; } |
| 163 |
}); |
| 164 |
}).catch(function () {}); |
| 165 |
} |
| 166 |
} |
| 167 |
|
| 168 |
|
| 169 |
function mark() { |
| 170 |
var m = location.hash.match(/^#L(\d+)(?:-L(\d+))?$/); |
| 171 |
document.querySelectorAll("tr.hl").forEach(function (r) { r.classList.remove("hl"); }); |
| 172 |
if (!m) { showBar(0, 0); return; } |
| 173 |
var a = +m[1], b = +(m[2] || m[1]); |
| 174 |
for (var i = Math.min(a, b); i <= Math.max(a, b); i++) { |
| 175 |
var row = document.getElementById("L" + i); |
| 176 |
if (row) row.classList.add("hl"); |
| 177 |
} |
| 178 |
var first = document.getElementById("L" + Math.min(a, b)); |
| 179 |
if (first && !mark.done) { first.scrollIntoView({ block: "center" }); mark.done = true; } |
| 180 |
showBar(Math.min(a, b), Math.max(a, b)); |
| 181 |
} |
| 182 |
|
| 183 |
var bar = document.querySelector(".linebar"); |
| 184 |
function showBar(a, b) { |
| 185 |
if (!bar) return; |
| 186 |
bar.hidden = !a; |
| 187 |
if (!a) return; |
| 188 |
bar.querySelector("[data-linebar-label]").textContent = a === b ? "Line " + a : "Lines " + a + "–" + b; |
| 189 |
bar.setAttribute("data-range", a + "-" + b); |
| 190 |
} |
| 191 |
function flash(btn) { var t = btn.textContent; btn.textContent = "Copied"; setTimeout(function () { btn.textContent = t; }, 1200); } |
| 192 |
if (bar) { |
| 193 |
bar.querySelector("[data-copy-lines]").addEventListener("click", function (ev) { |
| 194 |
var r = bar.getAttribute("data-range").split("-"), out = []; |
| 195 |
for (var i = +r[0]; i <= +r[1]; i++) { var row = document.getElementById("L" + i); if (row) out.push(row.querySelector("td.t").textContent); } |
| 196 |
navigator.clipboard.writeText(out.join("\n") + "\n").then(function () { flash(ev.target); }); |
| 197 |
}); |
| 198 |
var pl = bar.querySelector("[data-copy-permalink]"); |
| 199 |
if (pl) pl.addEventListener("click", function () { |
| 200 |
navigator.clipboard.writeText(new URL(document.body.getAttribute("data-permalink"), location.href).href + location.hash).then(function () { flash(pl); }); |
| 201 |
}); |
| 202 |
} |
| 203 |
function permalink() { var p = document.body.getAttribute("data-permalink"); return p ? p + location.hash : null; } |
| 204 |
window.addEventListener("hashchange", mark); |
| 205 |
mark(); |
| 206 |
document.querySelectorAll("table.code td.n").forEach(function (td) { |
| 207 |
td.addEventListener("click", function (e) { |
| 208 |
var n = td.parentNode.id; |
| 209 |
if (e.shiftKey && location.hash.match(/^#L(\d+)/)) location.hash = location.hash.replace(/^#(L\d+).*/, "$1-" + n); |
| 210 |
else location.hash = n; |
| 211 |
}); |
| 212 |
}); |
| 213 |
|
| 214 |
|
| 215 |
var liveUrl = document.body.getAttribute("data-flow-live"); |
| 216 |
if (liveUrl) { |
| 217 |
var tick = function () { |
| 218 |
var after = [].map.call(document.querySelectorAll("details[data-job]"), function (d) { |
| 219 |
return d.getAttribute("data-job") + ":" + d.querySelector("[data-log]").getAttribute("data-seq"); |
| 220 |
}).join(","); |
| 221 |
fetch(liveUrl + "?after=" + after, { headers: { accept: "application/json" } }) |
| 222 |
.then(function (r) { return r.json(); }) |
| 223 |
.then(function (s) { |
| 224 |
s.jobs.forEach(function (j) { |
| 225 |
var cls = "st-" + j.status; |
| 226 |
var node = document.querySelector("[data-job-node='" + j.id + "']"); |
| 227 |
if (node) { |
| 228 |
node.setAttribute("class", "node " + cls); |
| 229 |
node.querySelector("[data-glyph]").textContent = j.glyph; |
| 230 |
node.querySelector("[data-meta]").textContent = j.status + " · " + j.duration; |
| 231 |
} |
| 232 |
var d = document.querySelector("details[data-job='" + j.id + "']"); |
| 233 |
if (!d) return; |
| 234 |
d.className = "panel flow-job " + cls; |
| 235 |
var g = d.querySelector("summary [data-glyph]"); |
| 236 |
g.className = "flow-glyph " + cls; g.textContent = j.glyph; |
| 237 |
d.querySelector("summary [data-meta]").textContent = j.status + (j.exit_code !== null ? " · exit " + j.exit_code : "") + " · " + j.duration; |
| 238 |
if (j.status === "running" || j.status === "failed") d.open = true; |
| 239 |
var log = d.querySelector("[data-log]"); |
| 240 |
var stick = log.scrollTop + log.clientHeight >= log.scrollHeight - 4; |
| 241 |
j.lines.forEach(function (l) { |
| 242 |
var ln = document.createElement("span"); ln.className = "ln s-" + l.stream; |
| 243 |
var t = document.createElement("span"); t.className = "t"; t.textContent = (l.t / 1000).toFixed(1) + "s"; |
| 244 |
ln.appendChild(t); ln.appendChild(document.createTextNode(l.text)); |
| 245 |
log.appendChild(ln); log.appendChild(document.createTextNode("\n")); |
| 246 |
log.setAttribute("data-seq", l.seq); |
| 247 |
}); |
| 248 |
if (stick && j.lines.length) log.scrollTop = log.scrollHeight; |
| 249 |
}); |
| 250 |
var st = document.querySelector("[data-run-status]"); if (st) st.textContent = s.status; |
| 251 |
if (s.live) setTimeout(tick, 1500); else setTimeout(function () { location.reload(); }, 800); |
| 252 |
}) |
| 253 |
.catch(function () { setTimeout(tick, 5000); }); |
| 254 |
}; |
| 255 |
setTimeout(tick, 1500); |
| 256 |
} |
| 257 |
|
| 258 |
|
| 259 |
var pending = null; |
| 260 |
document.addEventListener("keydown", function (e) { |
| 261 |
if (e.target && /^(INPUT|TEXTAREA|SELECT)$/.test(e.target.tagName)) return; |
| 262 |
if (e.key === "/") { var s = document.querySelector("input[name=q]"); if (s) { e.preventDefault(); s.focus(); } return; } |
| 263 |
if (e.key === "y" && !e.ctrlKey && !e.metaKey && !e.altKey && permalink()) { history.replaceState(null, "", permalink()); pending = null; return; } |
| 264 |
if (e.key === "?") { var k = document.getElementById("keys"); if (k) k.hidden = !k.hidden; return; } |
| 265 |
var repo = document.body.getAttribute("data-repo"); |
| 266 |
if (pending === "g" && repo) { |
| 267 |
var to = { c: "", p: "/proposals", i: "/issues", h: "/changes/" + (document.body.getAttribute("data-ref") || "main"), b: "/bookmarks", t: "/trust" }[e.key]; |
| 268 |
if (to !== undefined) location.href = repo + to; |
| 269 |
pending = null; return; |
| 270 |
} |
| 271 |
pending = e.key === "g" ? "g" : null; |
| 272 |
}); |
| 273 |
|
| 274 |
|
| 275 |
|
| 276 |
|
| 277 |
var live = document.querySelector("[data-resolve-live]"); |
| 278 |
if (live && window.EventSource && window.fetch) { |
| 279 |
var url = live.getAttribute("data-resolve-live"), csrf = live.getAttribute("data-csrf"); |
| 280 |
var client = Math.random().toString(36).slice(2) + Date.now().toString(36); |
| 281 |
var present = document.querySelector("[data-live-present]"), landed = document.querySelector("[data-live-landed]"); |
| 282 |
var applying = false; |
| 283 |
var fieldsOf = function (region) { |
| 284 |
return region === "keep" |
| 285 |
? { radios: live.querySelectorAll('input[name="keep"]'), text: null } |
| 286 |
: { radios: live.querySelectorAll('input[name="r' + region + '"]'), text: live.querySelector('textarea[name="t' + region + '"]') }; |
| 287 |
}; |
| 288 |
var apply = function (region, c) { |
| 289 |
var f = fieldsOf(region); |
| 290 |
applying = true; |
| 291 |
f.radios.forEach(function (r) { r.checked = r.value === c.choice; }); |
| 292 |
if (f.text && c.choice === "text") f.text.value = c.text; |
| 293 |
applying = false; |
| 294 |
var sec = f.radios.length ? f.radios[0].closest("section") : null; |
| 295 |
if (sec) sec.setAttribute("title", "chosen by " + c.by); |
| 296 |
}; |
| 297 |
var send = function (region, choice, text) { |
| 298 |
fetch(url, { method: "POST", headers: { "content-type": "application/json" }, credentials: "same-origin", |
| 299 |
body: JSON.stringify({ _csrf: csrf, client: client, region: region, choice: choice, text: text || "" }) }); |
| 300 |
}; |
| 301 |
var timers = {}; |
| 302 |
live.addEventListener("change", function (ev) { |
| 303 |
var t = ev.target; |
| 304 |
if (applying || !t.name || t.type !== "radio") return; |
| 305 |
var region = t.name === "keep" ? "keep" : t.name.slice(1); |
| 306 |
var ta = live.querySelector('textarea[name="t' + region + '"]'); |
| 307 |
send(region, t.value, t.value === "text" && ta ? ta.value : ""); |
| 308 |
}); |
| 309 |
live.addEventListener("input", function (ev) { |
| 310 |
var t = ev.target; |
| 311 |
if (applying || t.tagName !== "TEXTAREA") return; |
| 312 |
var region = t.name.slice(1); |
| 313 |
live.querySelectorAll('input[name="r' + region + '"]').forEach(function (r) { r.checked = r.value === "text"; }); |
| 314 |
clearTimeout(timers[region]); |
| 315 |
timers[region] = setTimeout(function () { send(region, "text", t.value); }, 400); |
| 316 |
}); |
| 317 |
var es = new EventSource(url + "?client=" + encodeURIComponent(client)); |
| 318 |
var showPresent = function (names) { |
| 319 |
present.hidden = names.length < 2; |
| 320 |
present.textContent = "Resolving together: " + names.join(", ") + ". Choices are shared as you make them; the last choice for a conflict wins."; |
| 321 |
}; |
| 322 |
es.addEventListener("snapshot", function (e) { |
| 323 |
var d = JSON.parse(e.data); |
| 324 |
showPresent(d.present); |
| 325 |
Object.keys(d.choices).forEach(function (r) { apply(r, d.choices[r]); }); |
| 326 |
if (d.keep) apply("keep", d.keep); |
| 327 |
}); |
| 328 |
es.addEventListener("presence", function (e) { showPresent(JSON.parse(e.data).present); }); |
| 329 |
es.addEventListener("choice", function (e) { |
| 330 |
var d = JSON.parse(e.data); |
| 331 |
if (d.client !== client) apply(d.region, d.choice); |
| 332 |
}); |
| 333 |
es.addEventListener("landed", function (e) { |
| 334 |
var d = JSON.parse(e.data); |
| 335 |
es.close(); |
| 336 |
landed.hidden = false; |
| 337 |
landed.textContent = ""; |
| 338 |
landed.appendChild(document.createTextNode(d.by + " committed the resolution: ")); |
| 339 |
var a = document.createElement("a"); |
| 340 |
a.href = d.url; |
| 341 |
a.textContent = "see the change"; |
| 342 |
landed.appendChild(a); |
| 343 |
live.querySelectorAll("input, textarea, button").forEach(function (x) { x.disabled = true; }); |
| 344 |
}); |
| 345 |
} |
| 346 |
|
| 347 |
|
| 348 |
|
| 349 |
|
| 350 |
var plan = document.querySelector("[data-plan]"); |
| 351 |
if (plan && window.fetch) { |
| 352 |
var panel = document.querySelector("[data-plan-panel]"), from = null, moved = false; |
| 353 |
plan.querySelectorAll("[data-change]").forEach(function (a) { |
| 354 |
a.style.cursor = "grab"; |
| 355 |
a.addEventListener("pointerdown", function (ev) { from = a.getAttribute("data-change"); moved = false; ev.preventDefault(); }); |
| 356 |
a.addEventListener("pointermove", function () { if (from) moved = true; }); |
| 357 |
a.addEventListener("click", function (ev) { if (moved) ev.preventDefault(); }); |
| 358 |
}); |
| 359 |
document.addEventListener("pointerup", function (ev) { |
| 360 |
var start = from; |
| 361 |
from = null; |
| 362 |
if (!start) return; |
| 363 |
var el = document.elementFromPoint(ev.clientX, ev.clientY), onto = el && el.closest ? el.closest("[data-change]") : null; |
| 364 |
if (!onto || onto.getAttribute("data-change") === start) return; |
| 365 |
var body = new URLSearchParams({ _csrf: plan.getAttribute("data-csrf"), change: start, target: onto.getAttribute("data-change") }); |
| 366 |
fetch(plan.getAttribute("data-plan"), { method: "POST", credentials: "same-origin", body: body }) |
| 367 |
.then(function (r) { return r.json(); }) |
| 368 |
.then(function (d) { |
| 369 |
panel.hidden = false; |
| 370 |
panel.textContent = ""; |
| 371 |
if (d.error) { panel.textContent = d.error; return; } |
| 372 |
d.options.forEach(function (o) { |
| 373 |
var p = document.createElement("p"); |
| 374 |
p.appendChild(document.createTextNode(o.summary + " ")); |
| 375 |
var a = document.createElement("a"); |
| 376 |
a.href = o.vscode; |
| 377 |
a.textContent = "Apply in VS Code"; |
| 378 |
p.appendChild(a); |
| 379 |
var code = document.createElement("pre"); |
| 380 |
code.className = "snippet"; |
| 381 |
code.textContent = o.command; |
| 382 |
panel.appendChild(p); |
| 383 |
panel.appendChild(code); |
| 384 |
}); |
| 385 |
}); |
| 386 |
}); |
| 387 |
} |
| 388 |
})(); |