@youtyan/code-viewer 0.1.21 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/web/app.js +622 -45
- package/web/style.css +83 -36
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -243,10 +243,43 @@
|
|
|
243
243
|
}
|
|
244
244
|
return ranges;
|
|
245
245
|
}
|
|
246
|
-
function
|
|
246
|
+
function basenameMatchTier(loweredQuery, loweredBasename) {
|
|
247
|
+
if (loweredBasename === loweredQuery)
|
|
248
|
+
return 4;
|
|
249
|
+
if (loweredBasename.startsWith(`${loweredQuery}.`))
|
|
250
|
+
return 3;
|
|
251
|
+
if (loweredBasename.startsWith(loweredQuery))
|
|
252
|
+
return 2;
|
|
253
|
+
if (loweredBasename.includes(loweredQuery))
|
|
254
|
+
return 1;
|
|
255
|
+
return 0;
|
|
256
|
+
}
|
|
257
|
+
function pathMatchTier(loweredQuery, loweredPath, loweredBasename) {
|
|
258
|
+
if (loweredQuery.includes("/") && (loweredPath === loweredQuery || loweredPath.endsWith(`/${loweredQuery}`)))
|
|
259
|
+
return 4;
|
|
260
|
+
return basenameMatchTier(loweredQuery, loweredBasename);
|
|
261
|
+
}
|
|
262
|
+
function contiguousPathRange(loweredQuery, loweredPath, baseStart) {
|
|
263
|
+
const loweredBasename = loweredPath.slice(baseStart);
|
|
264
|
+
const basenameMatchStart = loweredBasename.indexOf(loweredQuery);
|
|
265
|
+
if (basenameMatchStart >= 0) {
|
|
266
|
+
const start = baseStart + basenameMatchStart;
|
|
267
|
+
return { start, end: start + loweredQuery.length };
|
|
268
|
+
}
|
|
269
|
+
if (loweredQuery.includes("/")) {
|
|
270
|
+
const pathMatchStart = loweredPath.endsWith(`/${loweredQuery}`) ? loweredPath.length - loweredQuery.length : loweredPath === loweredQuery ? 0 : -1;
|
|
271
|
+
if (pathMatchStart >= 0)
|
|
272
|
+
return {
|
|
273
|
+
start: pathMatchStart,
|
|
274
|
+
end: pathMatchStart + loweredQuery.length
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
function computeFuzzyMatch(query, path) {
|
|
247
280
|
const q = query.trim().toLowerCase();
|
|
248
281
|
if (!q)
|
|
249
|
-
return { score: 0, ranges: [] };
|
|
282
|
+
return { score: 0, ranges: [], tier: 0 };
|
|
250
283
|
const lowerPath = path.toLowerCase();
|
|
251
284
|
const baseStart = basenameStart(path);
|
|
252
285
|
const indices = [];
|
|
@@ -267,24 +300,28 @@
|
|
|
267
300
|
score += 12;
|
|
268
301
|
from = index + 1;
|
|
269
302
|
}
|
|
270
|
-
const first = indices[0]
|
|
303
|
+
const first = indices[0];
|
|
271
304
|
score -= Math.min(first, 40);
|
|
272
305
|
if (indices[0] >= baseStart)
|
|
273
306
|
score += 20;
|
|
274
307
|
const basename = lowerPath.slice(baseStart);
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
score
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
308
|
+
const tier = pathMatchTier(q, lowerPath, basename);
|
|
309
|
+
const contiguousRange = contiguousPathRange(q, lowerPath, baseStart);
|
|
310
|
+
return {
|
|
311
|
+
score,
|
|
312
|
+
ranges: contiguousRange ? [contiguousRange] : toRanges(indices),
|
|
313
|
+
tier
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function fuzzyMatchPath(query, path) {
|
|
317
|
+
const match = computeFuzzyMatch(query, path);
|
|
318
|
+
return match ? { score: match.score, ranges: match.ranges } : null;
|
|
282
319
|
}
|
|
283
320
|
function rankFuzzyPaths(query, items) {
|
|
284
321
|
return items.map((item) => {
|
|
285
|
-
const match =
|
|
286
|
-
return match ? { item, score: match.score, ranges: match.ranges } : null;
|
|
287
|
-
}).filter((item) => item !== null).sort((a, b) => b.score - a.score || a.item.path.localeCompare(b.item.path));
|
|
322
|
+
const match = computeFuzzyMatch(query, item.path);
|
|
323
|
+
return match ? { item, score: match.score, ranges: match.ranges, tier: match.tier } : null;
|
|
324
|
+
}).filter((item) => item !== null).sort((a, b) => b.tier - a.tier || b.score - a.score || a.item.path.localeCompare(b.item.path)).map(({ item, score, ranges }) => ({ item, score, ranges }));
|
|
288
325
|
}
|
|
289
326
|
function isGlobPathQuery(query) {
|
|
290
327
|
return /[*?]/.test(query.trim());
|
|
@@ -6481,7 +6518,7 @@ ${frontmatter.yaml}
|
|
|
6481
6518
|
});
|
|
6482
6519
|
}
|
|
6483
6520
|
function buildMarkdownToc(root) {
|
|
6484
|
-
const entries = Array.from(root.querySelectorAll("h1[id], h2[id], h3[id]")).map((heading2) => ({
|
|
6521
|
+
const entries = Array.from(root.querySelectorAll("h1[id], h2[id], h3[id], h4[id]")).map((heading2) => ({
|
|
6485
6522
|
id: heading2.id,
|
|
6486
6523
|
level: Number(heading2.tagName.slice(1)),
|
|
6487
6524
|
text: (heading2.textContent || "").replace(/#$/, "").trim()
|
|
@@ -6500,6 +6537,7 @@ ${frontmatter.yaml}
|
|
|
6500
6537
|
link2.href = `#${encodeURIComponent(entry.id)}`;
|
|
6501
6538
|
link2.dataset.target = entry.id;
|
|
6502
6539
|
link2.textContent = entry.text;
|
|
6540
|
+
link2.title = entry.text;
|
|
6503
6541
|
item.appendChild(link2);
|
|
6504
6542
|
list2.appendChild(item);
|
|
6505
6543
|
});
|
|
@@ -6884,7 +6922,11 @@ ${frontmatter.yaml}
|
|
|
6884
6922
|
const VIRTUAL_SOURCE_SIZE_THRESHOLD = 1024 * 1024;
|
|
6885
6923
|
const VIRTUAL_SOURCE_PAGE_SIZE = 2000;
|
|
6886
6924
|
const VIRTUAL_SOURCE_ROW_HEIGHT = 20;
|
|
6925
|
+
const VIRTUAL_SIDEBAR_THRESHOLD = 3000;
|
|
6926
|
+
const VIRTUAL_SIDEBAR_ROW_HEIGHT = 29;
|
|
6927
|
+
const VIRTUAL_SIDEBAR_OVERSCAN = 16;
|
|
6887
6928
|
const VIRTUAL_SOURCE_HIGHLIGHT_MAX_LINE_LENGTH = 2000;
|
|
6929
|
+
const TEST_RE = /(^|[/_.])(test|spec|__tests__)([/_.]|$)/i;
|
|
6888
6930
|
let highlightLoadPromise = null;
|
|
6889
6931
|
let sourceShikiLoadPromise = null;
|
|
6890
6932
|
let highlightConfigured = false;
|
|
@@ -6894,6 +6936,12 @@ ${frontmatter.yaml}
|
|
|
6894
6936
|
let REPO_SIDEBAR_LOAD = null;
|
|
6895
6937
|
let SIDEBAR_FILES = [];
|
|
6896
6938
|
let SIDEBAR_ON_FILE_CLICK;
|
|
6939
|
+
let SIDEBAR_TREE_ROOT = null;
|
|
6940
|
+
let SIDEBAR_TREE_ROWS = [];
|
|
6941
|
+
let SIDEBAR_VISIBLE_ROWS = [];
|
|
6942
|
+
let SIDEBAR_ROW_BY_PATH = new Map;
|
|
6943
|
+
let SIDEBAR_VIRTUAL_ACTIVE_PATH = "";
|
|
6944
|
+
const SIDEBAR_TREE_ITEMS_CACHE = new WeakMap;
|
|
6897
6945
|
let SERVER_SCOPE_OMIT_DIRS_DEFAULT = [];
|
|
6898
6946
|
let PENDING_G_SCOPE = null;
|
|
6899
6947
|
let PENDING_G_UNTIL = 0;
|
|
@@ -7584,6 +7632,22 @@ ${frontmatter.yaml}
|
|
|
7584
7632
|
attachSidebarToggle(restoreHost);
|
|
7585
7633
|
else if (sidebarHead)
|
|
7586
7634
|
attachSidebarToggle(sidebarHead);
|
|
7635
|
+
placeSidebarFilter();
|
|
7636
|
+
}
|
|
7637
|
+
function placeSidebarFilter() {
|
|
7638
|
+
const sidebarHead = document.querySelector(".sb-head");
|
|
7639
|
+
const filter = document.querySelector(".sb-filter-wrap");
|
|
7640
|
+
const list2 = document.querySelector("#filelist");
|
|
7641
|
+
if (!sidebarHead || !filter || !list2)
|
|
7642
|
+
return;
|
|
7643
|
+
const repoSidebar = isRepositorySidebarMode();
|
|
7644
|
+
if (repoSidebar && filter.parentElement !== sidebarHead) {
|
|
7645
|
+
sidebarHead.appendChild(filter);
|
|
7646
|
+
return;
|
|
7647
|
+
}
|
|
7648
|
+
if (!repoSidebar && filter.parentElement === sidebarHead) {
|
|
7649
|
+
sidebarHead.after(filter);
|
|
7650
|
+
}
|
|
7587
7651
|
}
|
|
7588
7652
|
function applySidebarHidden(hidden = STATE.sidebarHidden) {
|
|
7589
7653
|
STATE.sidebarHidden = hidden;
|
|
@@ -7859,6 +7923,301 @@ ${frontmatter.yaml}
|
|
|
7859
7923
|
}
|
|
7860
7924
|
}
|
|
7861
7925
|
}
|
|
7926
|
+
function treeNodeItems(node) {
|
|
7927
|
+
const cached = SIDEBAR_TREE_ITEMS_CACHE.get(node);
|
|
7928
|
+
if (cached)
|
|
7929
|
+
return cached;
|
|
7930
|
+
const items = [];
|
|
7931
|
+
for (const k of Object.keys(node.dirs)) {
|
|
7932
|
+
const d2 = node.dirs[k];
|
|
7933
|
+
items.push({ kind: "dir", sortKey: d2.minOrder, dir: d2 });
|
|
7934
|
+
}
|
|
7935
|
+
for (const f2 of node.files) {
|
|
7936
|
+
items.push({
|
|
7937
|
+
kind: "file",
|
|
7938
|
+
sortKey: f2.order != null ? f2.order : Infinity,
|
|
7939
|
+
file: f2
|
|
7940
|
+
});
|
|
7941
|
+
}
|
|
7942
|
+
items.sort((a2, b2) => a2.sortKey - b2.sortKey);
|
|
7943
|
+
SIDEBAR_TREE_ITEMS_CACHE.set(node, items);
|
|
7944
|
+
return items;
|
|
7945
|
+
}
|
|
7946
|
+
function createTreeDirRow(dir, depth, onFileClick) {
|
|
7947
|
+
const li = document.createElement("li");
|
|
7948
|
+
li.className = "tree-dir";
|
|
7949
|
+
li.tabIndex = -1;
|
|
7950
|
+
li.dataset.dirpath = dir.path;
|
|
7951
|
+
if (dir.explicit)
|
|
7952
|
+
li.dataset.explicit = "true";
|
|
7953
|
+
if (dir.children_omitted) {
|
|
7954
|
+
li.classList.add("children-omitted");
|
|
7955
|
+
li.classList.add(dir.children_omitted_reason === "heavy" ? "children-omitted-heavy" : "children-omitted-internal");
|
|
7956
|
+
li.title = dir.children_omitted_reason === "heavy" ? "Large generated/vendor directory: open the detail pane to browse its contents" : "Internal Git metadata is not browsed";
|
|
7957
|
+
}
|
|
7958
|
+
li.style.setProperty("--lvl-pad", `${12 + depth * 14}px`);
|
|
7959
|
+
const chev = document.createElement("span");
|
|
7960
|
+
if (dir.children_omitted) {
|
|
7961
|
+
chev.className = "chev-spacer";
|
|
7962
|
+
chev.setAttribute("aria-hidden", "true");
|
|
7963
|
+
} else {
|
|
7964
|
+
chev.className = "chev";
|
|
7965
|
+
setChevronIcon(chev);
|
|
7966
|
+
}
|
|
7967
|
+
li.appendChild(chev);
|
|
7968
|
+
const dirIcon = document.createElement("span");
|
|
7969
|
+
dirIcon.className = "dir-icon";
|
|
7970
|
+
li.appendChild(dirIcon);
|
|
7971
|
+
const label = document.createElement("span");
|
|
7972
|
+
label.className = "dir-label";
|
|
7973
|
+
const dn = document.createElement("span");
|
|
7974
|
+
dn.className = "dir-name";
|
|
7975
|
+
dn.textContent = dir.name;
|
|
7976
|
+
dn.title = dir.path;
|
|
7977
|
+
label.appendChild(dn);
|
|
7978
|
+
if (dir.children_omitted) {
|
|
7979
|
+
const omitted = document.createElement("span");
|
|
7980
|
+
omitted.className = "dir-omitted " + (dir.children_omitted_reason === "heavy" ? "dir-omitted-heavy" : "dir-omitted-internal");
|
|
7981
|
+
omitted.textContent = dir.children_omitted_reason === "heavy" ? "skipped" : "private";
|
|
7982
|
+
omitted.title = dir.children_omitted_reason === "heavy" ? "Tree expansion is skipped, but the directory detail can be opened" : "This directory cannot be opened from the browser";
|
|
7983
|
+
label.appendChild(omitted);
|
|
7984
|
+
}
|
|
7985
|
+
li.appendChild(label);
|
|
7986
|
+
li.appendChild(createOpenPathButton(dir.path, "directory", "open this folder in OS"));
|
|
7987
|
+
const updateIcon = () => {
|
|
7988
|
+
setFolderIcon(dirIcon, li.classList.contains("collapsed"));
|
|
7989
|
+
};
|
|
7990
|
+
const toggleDir = (e2) => {
|
|
7991
|
+
e2.stopPropagation();
|
|
7992
|
+
li.classList.toggle("collapsed");
|
|
7993
|
+
updateIcon();
|
|
7994
|
+
if (li.classList.contains("collapsed"))
|
|
7995
|
+
STATE.collapsedDirs.add(dir.path);
|
|
7996
|
+
else
|
|
7997
|
+
STATE.collapsedDirs.delete(dir.path);
|
|
7998
|
+
localStorage.setItem("gdp:collapsed-dirs", JSON.stringify([...STATE.collapsedDirs]));
|
|
7999
|
+
rerenderVirtualSidebar();
|
|
8000
|
+
};
|
|
8001
|
+
li.classList.toggle("collapsed", STATE.collapsedDirs.has(dir.path));
|
|
8002
|
+
updateIcon();
|
|
8003
|
+
if (!dir.children_omitted) {
|
|
8004
|
+
chev.addEventListener("click", toggleDir);
|
|
8005
|
+
dirIcon.addEventListener("click", toggleDir);
|
|
8006
|
+
}
|
|
8007
|
+
if (onFileClick) {
|
|
8008
|
+
li.addEventListener("click", (e2) => {
|
|
8009
|
+
e2.stopPropagation();
|
|
8010
|
+
if (dir.children_omitted_reason === "internal" || dir.children_omitted_reason === "truncated")
|
|
8011
|
+
return;
|
|
8012
|
+
onFileClick({
|
|
8013
|
+
path: dir.path,
|
|
8014
|
+
display_path: dir.path,
|
|
8015
|
+
type: "tree",
|
|
8016
|
+
children_omitted: dir.children_omitted,
|
|
8017
|
+
children_omitted_reason: dir.children_omitted_reason
|
|
8018
|
+
});
|
|
8019
|
+
scheduleMainSurfaceFocus();
|
|
8020
|
+
});
|
|
8021
|
+
} else {
|
|
8022
|
+
li.addEventListener("click", toggleDir);
|
|
8023
|
+
}
|
|
8024
|
+
return li;
|
|
8025
|
+
}
|
|
8026
|
+
function createTreeFileRow(f2, depth, onFileClick) {
|
|
8027
|
+
const li = document.createElement("li");
|
|
8028
|
+
li.className = "tree-file";
|
|
8029
|
+
li.tabIndex = -1;
|
|
8030
|
+
li.dataset.path = f2.path;
|
|
8031
|
+
li.classList.toggle("viewed", !onFileClick && STATE.viewedFiles.has(f2.path));
|
|
8032
|
+
li.classList.toggle("hidden-by-tests", STATE.hideTests && TEST_RE.test(f2.path || ""));
|
|
8033
|
+
li.style.setProperty("--lvl-pad", `${12 + depth * 14}px`);
|
|
8034
|
+
const spacer = document.createElement("span");
|
|
8035
|
+
spacer.className = "chev-spacer";
|
|
8036
|
+
li.appendChild(spacer);
|
|
8037
|
+
if (f2.status) {
|
|
8038
|
+
li.appendChild(fileBadge(f2.status));
|
|
8039
|
+
} else {
|
|
8040
|
+
const icon = document.createElement("span");
|
|
8041
|
+
icon.className = "d2h-icon-wrapper";
|
|
8042
|
+
icon.innerHTML = fileEntryIcon();
|
|
8043
|
+
li.appendChild(icon);
|
|
8044
|
+
}
|
|
8045
|
+
const name = document.createElement("span");
|
|
8046
|
+
name.className = "name";
|
|
8047
|
+
name.textContent = f2.path.split("/").pop();
|
|
8048
|
+
name.title = f2.path;
|
|
8049
|
+
li.appendChild(name);
|
|
8050
|
+
li.addEventListener("click", () => {
|
|
8051
|
+
if (onFileClick)
|
|
8052
|
+
onFileClick(f2);
|
|
8053
|
+
else
|
|
8054
|
+
scrollToFile(f2.path);
|
|
8055
|
+
scheduleMainSurfaceFocus();
|
|
8056
|
+
});
|
|
8057
|
+
if (!onFileClick)
|
|
8058
|
+
li.addEventListener("mouseenter", () => prefetchByPath(f2.path), {
|
|
8059
|
+
passive: true
|
|
8060
|
+
});
|
|
8061
|
+
return li;
|
|
8062
|
+
}
|
|
8063
|
+
function buildSidebarTreeRows(root) {
|
|
8064
|
+
const rows = [];
|
|
8065
|
+
const byPath = new Map;
|
|
8066
|
+
const walk = (node, depth) => {
|
|
8067
|
+
for (const item of treeNodeItems(node)) {
|
|
8068
|
+
if (item.kind === "dir") {
|
|
8069
|
+
const row = {
|
|
8070
|
+
kind: "dir",
|
|
8071
|
+
path: item.dir.path,
|
|
8072
|
+
name: item.dir.name,
|
|
8073
|
+
depth,
|
|
8074
|
+
dir: item.dir
|
|
8075
|
+
};
|
|
8076
|
+
rows.push(row);
|
|
8077
|
+
byPath.set(row.path, row);
|
|
8078
|
+
walk(item.dir, depth + 1);
|
|
8079
|
+
} else {
|
|
8080
|
+
const row = {
|
|
8081
|
+
kind: "file",
|
|
8082
|
+
path: item.file.path,
|
|
8083
|
+
name: item.file.path.split("/").pop() || item.file.path,
|
|
8084
|
+
depth,
|
|
8085
|
+
file: item.file
|
|
8086
|
+
};
|
|
8087
|
+
rows.push(row);
|
|
8088
|
+
byPath.set(row.path, row);
|
|
8089
|
+
}
|
|
8090
|
+
}
|
|
8091
|
+
};
|
|
8092
|
+
walk(root, 0);
|
|
8093
|
+
SIDEBAR_TREE_ROWS = rows;
|
|
8094
|
+
SIDEBAR_ROW_BY_PATH = byPath;
|
|
8095
|
+
}
|
|
8096
|
+
function computeVirtualSidebarVisibleRows() {
|
|
8097
|
+
if (!SIDEBAR_TREE_ROOT) {
|
|
8098
|
+
SIDEBAR_VISIBLE_ROWS = [];
|
|
8099
|
+
return;
|
|
8100
|
+
}
|
|
8101
|
+
const input = $("#sb-filter");
|
|
8102
|
+
const filter = compileFileFilter(input.value);
|
|
8103
|
+
const invalid = filter.kind === "invalid";
|
|
8104
|
+
input.toggleAttribute("aria-invalid", invalid);
|
|
8105
|
+
input.title = invalid ? filter.error || "invalid regular expression" : "";
|
|
8106
|
+
const filterActive = filter.kind !== "empty" && !invalid;
|
|
8107
|
+
const matches = invalid ? () => true : filter.match;
|
|
8108
|
+
const walk = (node, depth) => {
|
|
8109
|
+
let subtreeVisible = false;
|
|
8110
|
+
const rows = [];
|
|
8111
|
+
for (const item of treeNodeItems(node)) {
|
|
8112
|
+
if (item.kind === "dir") {
|
|
8113
|
+
const dirMatches = filterActive && matches(item.dir.path);
|
|
8114
|
+
const expanded = !item.dir.children_omitted && (filterActive || !STATE.collapsedDirs.has(item.dir.path));
|
|
8115
|
+
const child = walk(item.dir, depth + 1);
|
|
8116
|
+
const visible = item.dir.explicit && !filterActive ? true : dirMatches || child.visible;
|
|
8117
|
+
if (visible) {
|
|
8118
|
+
rows.push({
|
|
8119
|
+
kind: "dir",
|
|
8120
|
+
path: item.dir.path,
|
|
8121
|
+
name: item.dir.name,
|
|
8122
|
+
depth,
|
|
8123
|
+
dir: item.dir
|
|
8124
|
+
});
|
|
8125
|
+
if (expanded)
|
|
8126
|
+
rows.push(...child.rows);
|
|
8127
|
+
}
|
|
8128
|
+
subtreeVisible = subtreeVisible || visible;
|
|
8129
|
+
} else {
|
|
8130
|
+
const testHidden = STATE.hideTests && TEST_RE.test(item.file.path || "");
|
|
8131
|
+
const visible = !testHidden && matches(item.file.path || "");
|
|
8132
|
+
if (visible) {
|
|
8133
|
+
rows.push({
|
|
8134
|
+
kind: "file",
|
|
8135
|
+
path: item.file.path,
|
|
8136
|
+
name: item.file.path.split("/").pop() || item.file.path,
|
|
8137
|
+
depth,
|
|
8138
|
+
file: item.file
|
|
8139
|
+
});
|
|
8140
|
+
}
|
|
8141
|
+
subtreeVisible = subtreeVisible || visible;
|
|
8142
|
+
}
|
|
8143
|
+
}
|
|
8144
|
+
return { visible: subtreeVisible, rows };
|
|
8145
|
+
};
|
|
8146
|
+
SIDEBAR_VISIBLE_ROWS = walk(SIDEBAR_TREE_ROOT, 0).rows;
|
|
8147
|
+
}
|
|
8148
|
+
function sidebarVirtualRange() {
|
|
8149
|
+
const sidebar = document.querySelector("#sidebar");
|
|
8150
|
+
const scrollTop = sidebar?.scrollTop || 0;
|
|
8151
|
+
const height = sidebar?.clientHeight || window.innerHeight;
|
|
8152
|
+
const start = Math.max(0, Math.floor(scrollTop / VIRTUAL_SIDEBAR_ROW_HEIGHT) - VIRTUAL_SIDEBAR_OVERSCAN);
|
|
8153
|
+
const end = Math.min(SIDEBAR_VISIBLE_ROWS.length, Math.ceil((scrollTop + height) / VIRTUAL_SIDEBAR_ROW_HEIGHT) + VIRTUAL_SIDEBAR_OVERSCAN);
|
|
8154
|
+
return { start, end };
|
|
8155
|
+
}
|
|
8156
|
+
function renderVirtualSidebarWindow() {
|
|
8157
|
+
const ul = $("#filelist");
|
|
8158
|
+
if (!ul.classList.contains("tree-virtual"))
|
|
8159
|
+
return;
|
|
8160
|
+
const { start, end } = sidebarVirtualRange();
|
|
8161
|
+
const fragment = document.createDocumentFragment();
|
|
8162
|
+
for (let i2 = start;i2 < end; i2++) {
|
|
8163
|
+
const row = SIDEBAR_VISIBLE_ROWS[i2];
|
|
8164
|
+
const li = row.kind === "dir" && row.dir ? createTreeDirRow(row.dir, row.depth, SIDEBAR_ON_FILE_CLICK) : row.file ? createTreeFileRow(row.file, row.depth, SIDEBAR_ON_FILE_CLICK) : null;
|
|
8165
|
+
if (!li)
|
|
8166
|
+
continue;
|
|
8167
|
+
li.classList.toggle("active", row.path === SIDEBAR_VIRTUAL_ACTIVE_PATH);
|
|
8168
|
+
li.style.position = "absolute";
|
|
8169
|
+
li.style.top = `${i2 * VIRTUAL_SIDEBAR_ROW_HEIGHT}px`;
|
|
8170
|
+
li.style.left = "0";
|
|
8171
|
+
li.style.right = "0";
|
|
8172
|
+
fragment.appendChild(li);
|
|
8173
|
+
}
|
|
8174
|
+
ul.replaceChildren(fragment);
|
|
8175
|
+
ul.style.height = `${SIDEBAR_VISIBLE_ROWS.length * VIRTUAL_SIDEBAR_ROW_HEIGHT}px`;
|
|
8176
|
+
}
|
|
8177
|
+
function scrollVirtualSidebarPathIntoView(path) {
|
|
8178
|
+
const index = SIDEBAR_VISIBLE_ROWS.findIndex((row) => row.path === path);
|
|
8179
|
+
if (index < 0)
|
|
8180
|
+
return;
|
|
8181
|
+
const sidebar = document.querySelector("#sidebar");
|
|
8182
|
+
if (!sidebar)
|
|
8183
|
+
return;
|
|
8184
|
+
const ul = $("#filelist");
|
|
8185
|
+
const top = index * VIRTUAL_SIDEBAR_ROW_HEIGHT;
|
|
8186
|
+
const bottom = top + VIRTUAL_SIDEBAR_ROW_HEIGHT;
|
|
8187
|
+
const sidebarRect = sidebar.getBoundingClientRect();
|
|
8188
|
+
const stickyBottom = Math.max(sidebarRect.top, document.querySelector(".sb-head")?.getBoundingClientRect().bottom || sidebarRect.top, document.querySelector(".sb-filter-wrap")?.getBoundingClientRect().bottom || sidebarRect.top);
|
|
8189
|
+
const topPadding = Math.max(8, stickyBottom - sidebarRect.top + 8);
|
|
8190
|
+
const bottomPadding = 14;
|
|
8191
|
+
const listTop = ul.offsetTop;
|
|
8192
|
+
const maxHeight = Number.parseFloat(getComputedStyle(sidebar).maxHeight);
|
|
8193
|
+
const visibleHeight = Number.isFinite(maxHeight) && maxHeight > 0 ? Math.min(sidebar.clientHeight, maxHeight) : sidebar.clientHeight;
|
|
8194
|
+
const visibleTop = sidebar.scrollTop + topPadding - listTop;
|
|
8195
|
+
const visibleBottom = sidebar.scrollTop + visibleHeight - bottomPadding - listTop;
|
|
8196
|
+
if (top < visibleTop)
|
|
8197
|
+
sidebar.scrollTop = Math.max(0, top + listTop - topPadding);
|
|
8198
|
+
else if (bottom > visibleBottom)
|
|
8199
|
+
sidebar.scrollTop = bottom + listTop - visibleHeight + bottomPadding;
|
|
8200
|
+
renderVirtualSidebarWindow();
|
|
8201
|
+
}
|
|
8202
|
+
function rerenderVirtualSidebar() {
|
|
8203
|
+
const ul = document.querySelector("#filelist");
|
|
8204
|
+
if (!ul?.classList.contains("tree-virtual"))
|
|
8205
|
+
return;
|
|
8206
|
+
computeVirtualSidebarVisibleRows();
|
|
8207
|
+
renderVirtualSidebarWindow();
|
|
8208
|
+
}
|
|
8209
|
+
function renderVirtualTreeSidebar(root) {
|
|
8210
|
+
const ul = $("#filelist");
|
|
8211
|
+
SIDEBAR_TREE_ROOT = root;
|
|
8212
|
+
buildSidebarTreeRows(root);
|
|
8213
|
+
ul.classList.add("tree-virtual");
|
|
8214
|
+
ul.style.position = "relative";
|
|
8215
|
+
computeVirtualSidebarVisibleRows();
|
|
8216
|
+
renderVirtualSidebarWindow();
|
|
8217
|
+
document.querySelector("#sidebar")?.addEventListener("scroll", renderVirtualSidebarWindow, {
|
|
8218
|
+
passive: true
|
|
8219
|
+
});
|
|
8220
|
+
}
|
|
7862
8221
|
function renderFlat(files, ul, onFileClick) {
|
|
7863
8222
|
files.forEach((f2, i2) => {
|
|
7864
8223
|
const li = document.createElement("li");
|
|
@@ -7897,6 +8256,13 @@ ${frontmatter.yaml}
|
|
|
7897
8256
|
const ul = $("#filelist");
|
|
7898
8257
|
ul.innerHTML = "";
|
|
7899
8258
|
ul.classList.toggle("tree", STATE.sbView === "tree");
|
|
8259
|
+
ul.classList.remove("tree-virtual");
|
|
8260
|
+
ul.style.removeProperty("height");
|
|
8261
|
+
ul.style.removeProperty("position");
|
|
8262
|
+
SIDEBAR_TREE_ROOT = null;
|
|
8263
|
+
SIDEBAR_TREE_ROWS = [];
|
|
8264
|
+
SIDEBAR_VISIBLE_ROWS = [];
|
|
8265
|
+
SIDEBAR_ROW_BY_PATH = new Map;
|
|
7900
8266
|
STATE.files = files;
|
|
7901
8267
|
SIDEBAR_FILES = files;
|
|
7902
8268
|
SIDEBAR_ON_FILE_CLICK = onFileClick;
|
|
@@ -7904,7 +8270,10 @@ ${frontmatter.yaml}
|
|
|
7904
8270
|
REPO_SIDEBAR_REF = null;
|
|
7905
8271
|
if (STATE.sbView === "tree") {
|
|
7906
8272
|
const root = buildTree(files);
|
|
7907
|
-
|
|
8273
|
+
if (onFileClick && files.length >= VIRTUAL_SIDEBAR_THRESHOLD)
|
|
8274
|
+
renderVirtualTreeSidebar(root);
|
|
8275
|
+
else
|
|
8276
|
+
renderTreeNode(root, 0, ul, onFileClick);
|
|
7908
8277
|
} else {
|
|
7909
8278
|
renderFlat(files, ul, onFileClick);
|
|
7910
8279
|
}
|
|
@@ -7922,6 +8291,17 @@ ${frontmatter.yaml}
|
|
|
7922
8291
|
function setAllSidebarDirsCollapsed(collapsed) {
|
|
7923
8292
|
if (!collapsed)
|
|
7924
8293
|
STATE.collapsedDirs.clear();
|
|
8294
|
+
if ($("#filelist").classList.contains("tree-virtual")) {
|
|
8295
|
+
if (collapsed) {
|
|
8296
|
+
for (const row of SIDEBAR_TREE_ROWS) {
|
|
8297
|
+
if (row.kind === "dir")
|
|
8298
|
+
STATE.collapsedDirs.add(row.path);
|
|
8299
|
+
}
|
|
8300
|
+
}
|
|
8301
|
+
localStorage.setItem("gdp:collapsed-dirs", JSON.stringify([...STATE.collapsedDirs]));
|
|
8302
|
+
rerenderVirtualSidebar();
|
|
8303
|
+
return;
|
|
8304
|
+
}
|
|
7925
8305
|
$$("#filelist .tree-dir[data-dirpath]").forEach((li) => {
|
|
7926
8306
|
const path = li.dataset.dirpath || "";
|
|
7927
8307
|
if (!path)
|
|
@@ -8098,29 +8478,32 @@ ${frontmatter.yaml}
|
|
|
8098
8478
|
}
|
|
8099
8479
|
if (changed)
|
|
8100
8480
|
localStorage.setItem("gdp:collapsed-dirs", JSON.stringify([...STATE.collapsedDirs]));
|
|
8481
|
+
rerenderVirtualSidebar();
|
|
8101
8482
|
}
|
|
8102
8483
|
function markActive(path, options = {}) {
|
|
8103
8484
|
STATE.activeFile = path;
|
|
8485
|
+
SIDEBAR_VIRTUAL_ACTIVE_PATH = path;
|
|
8104
8486
|
if (options.reveal && STATE.sbView === "tree")
|
|
8105
8487
|
expandSidebarAncestors(path);
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8488
|
+
setActiveSidebarItem(sidebarItemByPath(path));
|
|
8489
|
+
if ($("#filelist").classList.contains("tree-virtual")) {
|
|
8490
|
+
renderVirtualSidebarWindow();
|
|
8491
|
+
scrollVirtualSidebarPathIntoView(path);
|
|
8492
|
+
return;
|
|
8493
|
+
}
|
|
8111
8494
|
if (options.reveal) {
|
|
8112
|
-
const active =
|
|
8495
|
+
const active = activeSidebarItem();
|
|
8113
8496
|
if (active)
|
|
8114
8497
|
requestAnimationFrame(() => scrollSidebarItemIntoView(active));
|
|
8115
8498
|
}
|
|
8116
8499
|
}
|
|
8117
8500
|
function applyViewedState() {
|
|
8501
|
+
if (isRepositorySidebarMode())
|
|
8502
|
+
return;
|
|
8118
8503
|
$$("#filelist li[data-path]").forEach((li) => {
|
|
8119
8504
|
const path = li.dataset.path || "";
|
|
8120
|
-
li.classList.toggle("viewed",
|
|
8505
|
+
li.classList.toggle("viewed", STATE.viewedFiles.has(path));
|
|
8121
8506
|
});
|
|
8122
|
-
if (isRepositorySidebarMode())
|
|
8123
|
-
return;
|
|
8124
8507
|
$$(".gdp-file-shell[data-path]").forEach((card) => {
|
|
8125
8508
|
const path = card.dataset.path || "";
|
|
8126
8509
|
const viewed = STATE.viewedFiles.has(path);
|
|
@@ -8129,11 +8512,16 @@ ${frontmatter.yaml}
|
|
|
8129
8512
|
}
|
|
8130
8513
|
function applyFilter() {
|
|
8131
8514
|
const input = $("#sb-filter");
|
|
8515
|
+
if ($("#filelist").classList.contains("tree-virtual")) {
|
|
8516
|
+
rerenderVirtualSidebar();
|
|
8517
|
+
return;
|
|
8518
|
+
}
|
|
8132
8519
|
const filter = compileFileFilter(input.value);
|
|
8133
8520
|
const invalid = filter.kind === "invalid";
|
|
8134
8521
|
input.toggleAttribute("aria-invalid", invalid);
|
|
8135
8522
|
input.title = invalid ? filter.error || "invalid regular expression" : "";
|
|
8136
8523
|
const matches = invalid ? () => true : filter.match;
|
|
8524
|
+
const filterActive = filter.kind !== "empty" && !invalid;
|
|
8137
8525
|
$$("#filelist li[data-path]").forEach((li) => {
|
|
8138
8526
|
const match2 = matches(li.dataset.path || "");
|
|
8139
8527
|
li.classList.toggle("hidden", !match2);
|
|
@@ -8144,21 +8532,51 @@ ${frontmatter.yaml}
|
|
|
8144
8532
|
card.classList.toggle("hidden-by-filter", !match2);
|
|
8145
8533
|
});
|
|
8146
8534
|
}
|
|
8147
|
-
updateTreeDirVisibility(matches,
|
|
8148
|
-
if (typeof applyViewedState === "function")
|
|
8535
|
+
updateTreeDirVisibility(matches, filterActive);
|
|
8536
|
+
if (!isRepositorySidebarMode() && typeof applyViewedState === "function")
|
|
8149
8537
|
applyViewedState();
|
|
8150
8538
|
}
|
|
8151
8539
|
function updateTreeDirVisibility(dirMatches, filterActive = false) {
|
|
8152
|
-
$$("#filelist .tree-dir")
|
|
8540
|
+
const dirs = $$("#filelist .tree-dir");
|
|
8541
|
+
for (let i2 = dirs.length - 1;i2 >= 0; i2--) {
|
|
8542
|
+
const dir = dirs[i2];
|
|
8153
8543
|
const childUl = dir.nextElementSibling;
|
|
8154
8544
|
if (!childUl?.classList.contains("tree-children"))
|
|
8155
|
-
|
|
8156
|
-
|
|
8545
|
+
continue;
|
|
8546
|
+
let anyVisible = false;
|
|
8547
|
+
for (const child of childUl.children) {
|
|
8548
|
+
if (!(child instanceof HTMLElement))
|
|
8549
|
+
continue;
|
|
8550
|
+
if (child.classList.contains("tree-file") && !child.classList.contains("hidden") && !child.classList.contains("hidden-by-tests")) {
|
|
8551
|
+
anyVisible = true;
|
|
8552
|
+
break;
|
|
8553
|
+
}
|
|
8554
|
+
if (child.classList.contains("tree-dir") && !child.classList.contains("hidden") && !child.classList.contains("hidden-by-tests")) {
|
|
8555
|
+
anyVisible = true;
|
|
8556
|
+
break;
|
|
8557
|
+
}
|
|
8558
|
+
}
|
|
8157
8559
|
const explicitVisible = dir.dataset.explicit === "true" && !filterActive;
|
|
8158
8560
|
const selfMatches = filterActive && !!dirMatches && dirMatches(dir.dataset.dirpath || "");
|
|
8159
8561
|
dir.classList.toggle("hidden", !anyVisible && !explicitVisible && !selfMatches);
|
|
8562
|
+
}
|
|
8563
|
+
}
|
|
8564
|
+
let SIDEBAR_FILTER_RAF = 0;
|
|
8565
|
+
function scheduleApplyFilter() {
|
|
8566
|
+
if (SIDEBAR_FILTER_RAF)
|
|
8567
|
+
cancelAnimationFrame(SIDEBAR_FILTER_RAF);
|
|
8568
|
+
SIDEBAR_FILTER_RAF = requestAnimationFrame(() => {
|
|
8569
|
+
SIDEBAR_FILTER_RAF = 0;
|
|
8570
|
+
applyFilter();
|
|
8160
8571
|
});
|
|
8161
8572
|
}
|
|
8573
|
+
function flushSidebarFilter() {
|
|
8574
|
+
if (!SIDEBAR_FILTER_RAF)
|
|
8575
|
+
return;
|
|
8576
|
+
cancelAnimationFrame(SIDEBAR_FILTER_RAF);
|
|
8577
|
+
SIDEBAR_FILTER_RAF = 0;
|
|
8578
|
+
applyFilter();
|
|
8579
|
+
}
|
|
8162
8580
|
let SERVER_GENERATION = 0;
|
|
8163
8581
|
let CLIENT_REQ_SEQ = 0;
|
|
8164
8582
|
const LOAD_QUEUE = [];
|
|
@@ -11705,8 +12123,97 @@ ${frontmatter.yaml}
|
|
|
11705
12123
|
}
|
|
11706
12124
|
return true;
|
|
11707
12125
|
}
|
|
12126
|
+
const SIDEBAR_ITEM_SELECTOR = "#filelist li[data-path], #filelist .tree-dir[data-dirpath]";
|
|
12127
|
+
const ACTIVE_SIDEBAR_ITEM_SELECTOR = "#filelist li.active[data-path], #filelist .tree-dir.active[data-dirpath]";
|
|
12128
|
+
function sidebarItemPath(item) {
|
|
12129
|
+
return item.dataset.path || item.dataset.dirpath || "";
|
|
12130
|
+
}
|
|
12131
|
+
function activeSidebarItem() {
|
|
12132
|
+
return document.querySelector(ACTIVE_SIDEBAR_ITEM_SELECTOR);
|
|
12133
|
+
}
|
|
12134
|
+
function sidebarItemByPath(path) {
|
|
12135
|
+
if (isVirtualSidebarActive() && SIDEBAR_ROW_BY_PATH.has(path)) {
|
|
12136
|
+
return document.querySelector(`#filelist li[data-path="${CSS.escape(path)}"], #filelist .tree-dir[data-dirpath="${CSS.escape(path)}"]`) || null;
|
|
12137
|
+
}
|
|
12138
|
+
const escaped = CSS.escape(path);
|
|
12139
|
+
return document.querySelector(`#filelist li[data-path="${escaped}"], #filelist .tree-dir[data-dirpath="${escaped}"]`);
|
|
12140
|
+
}
|
|
12141
|
+
function setActiveSidebarItem(target) {
|
|
12142
|
+
document.querySelectorAll(ACTIVE_SIDEBAR_ITEM_SELECTOR).forEach((item) => {
|
|
12143
|
+
if (item !== target)
|
|
12144
|
+
item.classList.remove("active");
|
|
12145
|
+
});
|
|
12146
|
+
target?.classList.add("active");
|
|
12147
|
+
}
|
|
11708
12148
|
function visibleSidebarItems() {
|
|
11709
|
-
return $$(
|
|
12149
|
+
return $$(SIDEBAR_ITEM_SELECTOR).filter(isSidebarRowVisible);
|
|
12150
|
+
}
|
|
12151
|
+
function isVirtualSidebarActive() {
|
|
12152
|
+
return $("#filelist").classList.contains("tree-virtual");
|
|
12153
|
+
}
|
|
12154
|
+
function virtualSidebarActiveIndex() {
|
|
12155
|
+
const activePath = SIDEBAR_VIRTUAL_ACTIVE_PATH || STATE.activeFile || "";
|
|
12156
|
+
return SIDEBAR_VISIBLE_ROWS.findIndex((row) => row.path === activePath);
|
|
12157
|
+
}
|
|
12158
|
+
function selectVirtualSidebarIndex(index, options) {
|
|
12159
|
+
if (!SIDEBAR_VISIBLE_ROWS.length)
|
|
12160
|
+
return null;
|
|
12161
|
+
const safeIndex = Math.max(0, Math.min(SIDEBAR_VISIBLE_ROWS.length - 1, index));
|
|
12162
|
+
const row = SIDEBAR_VISIBLE_ROWS[safeIndex];
|
|
12163
|
+
if (!row)
|
|
12164
|
+
return null;
|
|
12165
|
+
markActive(row.path);
|
|
12166
|
+
scrollVirtualSidebarPathIntoView(row.path);
|
|
12167
|
+
if (options?.open) {
|
|
12168
|
+
if (row.kind === "dir" && row.dir && SIDEBAR_ON_FILE_CLICK) {
|
|
12169
|
+
SIDEBAR_ON_FILE_CLICK({
|
|
12170
|
+
path: row.dir.path,
|
|
12171
|
+
display_path: row.dir.path,
|
|
12172
|
+
type: "tree",
|
|
12173
|
+
children_omitted: row.dir.children_omitted,
|
|
12174
|
+
children_omitted_reason: row.dir.children_omitted_reason
|
|
12175
|
+
});
|
|
12176
|
+
} else if (row.file && SIDEBAR_ON_FILE_CLICK) {
|
|
12177
|
+
SIDEBAR_ON_FILE_CLICK(row.file);
|
|
12178
|
+
}
|
|
12179
|
+
}
|
|
12180
|
+
return row;
|
|
12181
|
+
}
|
|
12182
|
+
function visibleSidebarItemFrom(current, direction) {
|
|
12183
|
+
const root = document.querySelector("#filelist");
|
|
12184
|
+
if (!current.isConnected)
|
|
12185
|
+
return null;
|
|
12186
|
+
if (!root)
|
|
12187
|
+
return null;
|
|
12188
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
|
|
12189
|
+
acceptNode(node) {
|
|
12190
|
+
if (!(node instanceof HTMLElement))
|
|
12191
|
+
return NodeFilter.FILTER_SKIP;
|
|
12192
|
+
if (node.classList.contains("tree-children")) {
|
|
12193
|
+
const dir = node.previousElementSibling;
|
|
12194
|
+
if (dir?.classList.contains("collapsed") || dir?.classList.contains("hidden") || dir?.classList.contains("hidden-by-tests"))
|
|
12195
|
+
return NodeFilter.FILTER_REJECT;
|
|
12196
|
+
}
|
|
12197
|
+
if (!node.matches(SIDEBAR_ITEM_SELECTOR))
|
|
12198
|
+
return NodeFilter.FILTER_SKIP;
|
|
12199
|
+
return isSidebarRowVisible(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
|
|
12200
|
+
}
|
|
12201
|
+
});
|
|
12202
|
+
walker.currentNode = current;
|
|
12203
|
+
const next = direction === 1 ? walker.nextNode() : walker.previousNode();
|
|
12204
|
+
return next instanceof HTMLElement ? next : null;
|
|
12205
|
+
}
|
|
12206
|
+
function adjacentVisibleSidebarItem(direction) {
|
|
12207
|
+
const active = activeSidebarItem();
|
|
12208
|
+
if (!active) {
|
|
12209
|
+
const items = visibleSidebarItems();
|
|
12210
|
+
return direction === 1 ? items[0] || null : items[items.length - 1] || null;
|
|
12211
|
+
}
|
|
12212
|
+
if (!isSidebarRowVisible(active)) {
|
|
12213
|
+
const items = visibleSidebarItems();
|
|
12214
|
+
return direction === 1 ? items[0] || null : items[items.length - 1] || null;
|
|
12215
|
+
}
|
|
12216
|
+
return visibleSidebarItemFrom(active, direction) || active;
|
|
11710
12217
|
}
|
|
11711
12218
|
function scrollSidebarItemIntoView(item, block2 = "nearest") {
|
|
11712
12219
|
const sidebar = document.querySelector("#sidebar");
|
|
@@ -11738,6 +12245,14 @@ ${frontmatter.yaml}
|
|
|
11738
12245
|
return document.body.classList.contains("gdp-repo-page") || document.body.classList.contains("gdp-repo-blob-page");
|
|
11739
12246
|
}
|
|
11740
12247
|
function moveActiveSidebarItem(direction) {
|
|
12248
|
+
if (isVirtualSidebarActive()) {
|
|
12249
|
+
const current2 = virtualSidebarActiveIndex();
|
|
12250
|
+
const start = current2 < 0 ? direction === 1 ? 0 : SIDEBAR_VISIBLE_ROWS.length - 1 : current2 + direction;
|
|
12251
|
+
const row = selectVirtualSidebarIndex(start);
|
|
12252
|
+
if (row?.file)
|
|
12253
|
+
prefetchByPath(row.file.path);
|
|
12254
|
+
return;
|
|
12255
|
+
}
|
|
11741
12256
|
const items = visibleSidebarItems();
|
|
11742
12257
|
if (!items.length)
|
|
11743
12258
|
return;
|
|
@@ -11754,6 +12269,16 @@ ${frontmatter.yaml}
|
|
|
11754
12269
|
prefetchByPath(target.dataset.path);
|
|
11755
12270
|
}
|
|
11756
12271
|
function moveActiveSidebarPage(direction) {
|
|
12272
|
+
if (isVirtualSidebarActive()) {
|
|
12273
|
+
const sidebar2 = document.querySelector("#sidebar");
|
|
12274
|
+
const halfPageRows2 = Math.max(1, Math.floor((sidebar2?.clientHeight || window.innerHeight) / 2 / VIRTUAL_SIDEBAR_ROW_HEIGHT));
|
|
12275
|
+
const current2 = virtualSidebarActiveIndex();
|
|
12276
|
+
const start2 = current2 < 0 ? 0 : current2;
|
|
12277
|
+
const row = selectVirtualSidebarIndex(start2 + direction * halfPageRows2);
|
|
12278
|
+
if (row?.file)
|
|
12279
|
+
prefetchByPath(row.file.path);
|
|
12280
|
+
return;
|
|
12281
|
+
}
|
|
11757
12282
|
const items = visibleSidebarItems();
|
|
11758
12283
|
if (!items.length)
|
|
11759
12284
|
return;
|
|
@@ -11776,6 +12301,12 @@ ${frontmatter.yaml}
|
|
|
11776
12301
|
prefetchByPath(target.dataset.path);
|
|
11777
12302
|
}
|
|
11778
12303
|
function moveActiveSidebarToEdge(edge) {
|
|
12304
|
+
if (isVirtualSidebarActive()) {
|
|
12305
|
+
const row = selectVirtualSidebarIndex(edge === "top" ? 0 : SIDEBAR_VISIBLE_ROWS.length - 1);
|
|
12306
|
+
if (row?.file)
|
|
12307
|
+
prefetchByPath(row.file.path);
|
|
12308
|
+
return;
|
|
12309
|
+
}
|
|
11779
12310
|
const items = visibleSidebarItems();
|
|
11780
12311
|
const repoSidebar = isRepositorySidebarMode();
|
|
11781
12312
|
const target = edge === "top" ? items[0] : items[items.length - 1];
|
|
@@ -11791,6 +12322,21 @@ ${frontmatter.yaml}
|
|
|
11791
12322
|
prefetchByPath(target.dataset.path);
|
|
11792
12323
|
}
|
|
11793
12324
|
function setActiveSidebarDirectoryCollapsed(collapsed) {
|
|
12325
|
+
if (isVirtualSidebarActive()) {
|
|
12326
|
+
const row = SIDEBAR_VISIBLE_ROWS[virtualSidebarActiveIndex()];
|
|
12327
|
+
if (row?.kind !== "dir" || !row.dir || row.dir.children_omitted)
|
|
12328
|
+
return;
|
|
12329
|
+
if (STATE.collapsedDirs.has(row.path) === collapsed)
|
|
12330
|
+
return;
|
|
12331
|
+
if (collapsed)
|
|
12332
|
+
STATE.collapsedDirs.add(row.path);
|
|
12333
|
+
else
|
|
12334
|
+
STATE.collapsedDirs.delete(row.path);
|
|
12335
|
+
localStorage.setItem("gdp:collapsed-dirs", JSON.stringify([...STATE.collapsedDirs]));
|
|
12336
|
+
rerenderVirtualSidebar();
|
|
12337
|
+
scrollVirtualSidebarPathIntoView(row.path);
|
|
12338
|
+
return;
|
|
12339
|
+
}
|
|
11794
12340
|
const active = document.querySelector("#filelist .tree-dir.active[data-dirpath]");
|
|
11795
12341
|
if (!active)
|
|
11796
12342
|
return;
|
|
@@ -11801,6 +12347,13 @@ ${frontmatter.yaml}
|
|
|
11801
12347
|
control.click();
|
|
11802
12348
|
}
|
|
11803
12349
|
function toggleActiveSidebarDirectoryCollapsed() {
|
|
12350
|
+
if (isVirtualSidebarActive()) {
|
|
12351
|
+
const row = SIDEBAR_VISIBLE_ROWS[virtualSidebarActiveIndex()];
|
|
12352
|
+
if (row?.kind !== "dir" || !row.dir || row.dir.children_omitted)
|
|
12353
|
+
return;
|
|
12354
|
+
setActiveSidebarDirectoryCollapsed(!STATE.collapsedDirs.has(row.path));
|
|
12355
|
+
return;
|
|
12356
|
+
}
|
|
11804
12357
|
const active = document.querySelector("#filelist .tree-dir.active[data-dirpath]");
|
|
11805
12358
|
if (!active)
|
|
11806
12359
|
return;
|
|
@@ -11809,11 +12362,23 @@ ${frontmatter.yaml}
|
|
|
11809
12362
|
control.click();
|
|
11810
12363
|
}
|
|
11811
12364
|
function openActiveSidebarItem() {
|
|
12365
|
+
if (isVirtualSidebarActive()) {
|
|
12366
|
+
const index = virtualSidebarActiveIndex();
|
|
12367
|
+
if (index >= 0)
|
|
12368
|
+
selectVirtualSidebarIndex(index, { open: true });
|
|
12369
|
+
return;
|
|
12370
|
+
}
|
|
11812
12371
|
const active = document.querySelector("#filelist li.active[data-path], #filelist .tree-dir.active[data-dirpath]");
|
|
11813
12372
|
if (active && isSidebarRowVisible(active))
|
|
11814
12373
|
active.click();
|
|
11815
12374
|
}
|
|
11816
12375
|
function jumpToActiveOrFirstFilteredItem() {
|
|
12376
|
+
if (isVirtualSidebarActive()) {
|
|
12377
|
+
const current = virtualSidebarActiveIndex();
|
|
12378
|
+
selectVirtualSidebarIndex(current >= 0 ? current : 0, { open: true });
|
|
12379
|
+
$("#sb-filter").blur();
|
|
12380
|
+
return;
|
|
12381
|
+
}
|
|
11817
12382
|
const items = visibleSidebarItems();
|
|
11818
12383
|
const active = items.find((li) => li.classList.contains("active"));
|
|
11819
12384
|
const target = active || items[0];
|
|
@@ -11824,17 +12389,20 @@ ${frontmatter.yaml}
|
|
|
11824
12389
|
}
|
|
11825
12390
|
const sbFilter = $("#sb-filter");
|
|
11826
12391
|
if (sbFilter) {
|
|
11827
|
-
sbFilter.addEventListener("input", () =>
|
|
12392
|
+
sbFilter.addEventListener("input", () => scheduleApplyFilter());
|
|
11828
12393
|
sbFilter.addEventListener("keydown", (e2) => {
|
|
11829
12394
|
if (e2.key === "Enter") {
|
|
11830
12395
|
e2.preventDefault();
|
|
12396
|
+
flushSidebarFilter();
|
|
11831
12397
|
jumpToActiveOrFirstFilteredItem();
|
|
11832
12398
|
} else if (e2.key === "ArrowDown" || e2.key === "ArrowUp") {
|
|
11833
12399
|
e2.preventDefault();
|
|
12400
|
+
flushSidebarFilter();
|
|
11834
12401
|
moveActiveSidebarItem(e2.key === "ArrowDown" ? 1 : -1);
|
|
11835
12402
|
} else if (e2.key === "Escape") {
|
|
11836
12403
|
if (sbFilter.value) {
|
|
11837
12404
|
sbFilter.value = "";
|
|
12405
|
+
flushSidebarFilter();
|
|
11838
12406
|
applyFilter();
|
|
11839
12407
|
} else {
|
|
11840
12408
|
sbFilter.blur();
|
|
@@ -12322,16 +12890,24 @@ ${frontmatter.yaml}
|
|
|
12322
12890
|
}
|
|
12323
12891
|
if (action === "sidebar-next" || action === "sidebar-previous") {
|
|
12324
12892
|
const repoSidebar = isRepositorySidebarMode();
|
|
12325
|
-
const
|
|
12326
|
-
|
|
12893
|
+
const direction = action === "sidebar-next" ? 1 : -1;
|
|
12894
|
+
const diffItems = repoSidebar ? [] : $$("#filelist li[data-path]:not(.hidden):not(.hidden-by-tests)");
|
|
12895
|
+
let diffIndex = diffItems.findIndex((li) => li.classList.contains("active"));
|
|
12896
|
+
if (!repoSidebar)
|
|
12897
|
+
diffIndex = diffIndex < 0 ? 0 : Math.max(0, Math.min(diffItems.length - 1, diffIndex + direction));
|
|
12898
|
+
const target = repoSidebar ? isVirtualSidebarActive() ? null : adjacentVisibleSidebarItem(direction) : diffItems[diffIndex];
|
|
12899
|
+
if (repoSidebar && isVirtualSidebarActive()) {
|
|
12900
|
+
const current = virtualSidebarActiveIndex();
|
|
12901
|
+
const start = current < 0 ? direction === 1 ? 0 : SIDEBAR_VISIBLE_ROWS.length - 1 : current + direction;
|
|
12902
|
+
const row = selectVirtualSidebarIndex(start);
|
|
12903
|
+
const next = row ? SIDEBAR_VISIBLE_ROWS[Math.max(0, Math.min(SIDEBAR_VISIBLE_ROWS.length - 1, SIDEBAR_VISIBLE_ROWS.indexOf(row) + direction))] : null;
|
|
12904
|
+
if (!repeated && next?.file)
|
|
12905
|
+
prefetchByPath(next.file.path);
|
|
12327
12906
|
return true;
|
|
12328
|
-
|
|
12329
|
-
if (
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
idx = action === "sidebar-next" ? Math.min(items.length - 1, idx + 1) : Math.max(0, idx - 1);
|
|
12333
|
-
const target = items[idx];
|
|
12334
|
-
const path = target?.dataset.path || target?.dataset.dirpath;
|
|
12907
|
+
}
|
|
12908
|
+
if (!target)
|
|
12909
|
+
return true;
|
|
12910
|
+
const path = sidebarItemPath(target);
|
|
12335
12911
|
if (!repoSidebar && target) {
|
|
12336
12912
|
target.click();
|
|
12337
12913
|
scrollSidebarItemIntoView(target);
|
|
@@ -12339,9 +12915,8 @@ ${frontmatter.yaml}
|
|
|
12339
12915
|
markActive(path);
|
|
12340
12916
|
scrollSidebarItemIntoView(target);
|
|
12341
12917
|
}
|
|
12342
|
-
const
|
|
12343
|
-
|
|
12344
|
-
if (nextItem && nextItem !== target && nextItem.dataset.path)
|
|
12918
|
+
const nextItem = repoSidebar ? visibleSidebarItemFrom(target, direction) : diffItems[Math.max(0, Math.min(diffItems.length - 1, diffIndex + direction))];
|
|
12919
|
+
if (!repeated && nextItem && nextItem !== target && nextItem.dataset.path)
|
|
12345
12920
|
prefetchByPath(nextItem.dataset.path);
|
|
12346
12921
|
return true;
|
|
12347
12922
|
}
|
|
@@ -12846,7 +13421,6 @@ ${frontmatter.yaml}
|
|
|
12846
13421
|
if (e2.key === "gdp:syntax-highlight")
|
|
12847
13422
|
setSyntaxHighlight(e2.newValue !== "0");
|
|
12848
13423
|
});
|
|
12849
|
-
const TEST_RE = /(^|[/_.])(test|spec|__tests__)([/_.]|$)/i;
|
|
12850
13424
|
function applyHideTests() {
|
|
12851
13425
|
const btn = $("#hide-tests");
|
|
12852
13426
|
if (btn)
|
|
@@ -12859,7 +13433,10 @@ ${frontmatter.yaml}
|
|
|
12859
13433
|
const isTest = TEST_RE.test(li.dataset.path || "");
|
|
12860
13434
|
li.classList.toggle("hidden-by-tests", STATE.hideTests && isTest);
|
|
12861
13435
|
});
|
|
12862
|
-
|
|
13436
|
+
if (isVirtualSidebarActive())
|
|
13437
|
+
rerenderVirtualSidebar();
|
|
13438
|
+
else
|
|
13439
|
+
updateTreeDirVisibility();
|
|
12863
13440
|
if (typeof applyViewedState === "function")
|
|
12864
13441
|
applyViewedState();
|
|
12865
13442
|
}
|
package/web/style.css
CHANGED
|
@@ -1352,6 +1352,16 @@ body.gdp-help-page #content {
|
|
|
1352
1352
|
#filelist.tree {
|
|
1353
1353
|
padding: 4px 0 0;
|
|
1354
1354
|
}
|
|
1355
|
+
#filelist.tree.tree-virtual {
|
|
1356
|
+
padding: 0;
|
|
1357
|
+
}
|
|
1358
|
+
#filelist.tree.tree-virtual .tree-dir,
|
|
1359
|
+
#filelist.tree.tree-virtual .tree-file {
|
|
1360
|
+
height: 29px;
|
|
1361
|
+
min-height: 29px;
|
|
1362
|
+
overflow: hidden;
|
|
1363
|
+
box-sizing: border-box;
|
|
1364
|
+
}
|
|
1355
1365
|
#filelist.tree .tree-dir {
|
|
1356
1366
|
display: grid;
|
|
1357
1367
|
grid-template-columns: 16px 16px minmax(0, 1fr) 22px;
|
|
@@ -2590,49 +2600,53 @@ table.d2h-diff-table tr.gdp-diff-line-target > td:first-child {
|
|
|
2590
2600
|
}
|
|
2591
2601
|
.gdp-html-preview {
|
|
2592
2602
|
width: 100%;
|
|
2593
|
-
min-height:
|
|
2603
|
+
min-height: calc(100vh - var(--global-header-h) - 118px);
|
|
2594
2604
|
background: var(--bg);
|
|
2595
2605
|
}
|
|
2596
2606
|
.gdp-html-preview iframe {
|
|
2597
2607
|
display: block;
|
|
2598
2608
|
width: 100%;
|
|
2599
|
-
min-height:
|
|
2609
|
+
min-height: calc(100vh - var(--global-header-h) - 118px);
|
|
2600
2610
|
border: 0;
|
|
2601
2611
|
background: #fff;
|
|
2602
2612
|
}
|
|
2603
2613
|
.gdp-markdown-layout {
|
|
2604
2614
|
display: grid;
|
|
2605
|
-
grid-template-columns:
|
|
2606
|
-
gap:
|
|
2615
|
+
grid-template-columns: 280px minmax(0, 1fr);
|
|
2616
|
+
gap: 28px;
|
|
2607
2617
|
align-items: start;
|
|
2608
2618
|
}
|
|
2609
|
-
.gdp-standalone-source .gdp-markdown-layout {
|
|
2610
|
-
grid-template-columns: minmax(0, 1fr);
|
|
2611
|
-
}
|
|
2612
|
-
.gdp-standalone-source .gdp-markdown-toc {
|
|
2613
|
-
display: none;
|
|
2614
|
-
}
|
|
2615
2619
|
.gdp-markdown-toc {
|
|
2616
2620
|
position: sticky;
|
|
2617
|
-
top:
|
|
2618
|
-
max-height: calc(100vh -
|
|
2621
|
+
top: calc(var(--global-header-h) + 16px);
|
|
2622
|
+
max-height: calc(100vh - var(--global-header-h) - 40px);
|
|
2619
2623
|
overflow: auto;
|
|
2620
|
-
padding:
|
|
2621
|
-
border-right: 1px solid var(--border);
|
|
2622
|
-
background:
|
|
2624
|
+
padding: 8px 12px 10px 0;
|
|
2625
|
+
border-right: 1px solid var(--border-muted);
|
|
2626
|
+
background: transparent;
|
|
2623
2627
|
font-size: 13px;
|
|
2624
2628
|
line-height: 1.45;
|
|
2629
|
+
scrollbar-gutter: stable;
|
|
2630
|
+
scrollbar-width: thin;
|
|
2631
|
+
scrollbar-color: var(--border) transparent;
|
|
2632
|
+
}
|
|
2633
|
+
.gdp-markdown-toc::-webkit-scrollbar {
|
|
2634
|
+
width: 8px;
|
|
2635
|
+
}
|
|
2636
|
+
.gdp-markdown-toc::-webkit-scrollbar-thumb {
|
|
2637
|
+
border-radius: 4px;
|
|
2638
|
+
background: var(--border);
|
|
2625
2639
|
}
|
|
2626
2640
|
.gdp-markdown-toc::before {
|
|
2627
|
-
content: "
|
|
2641
|
+
content: "On this page";
|
|
2628
2642
|
display: block;
|
|
2629
|
-
margin: 0
|
|
2630
|
-
padding
|
|
2643
|
+
margin: 0 0 10px 2px;
|
|
2644
|
+
padding: 0 8px 10px;
|
|
2631
2645
|
border-bottom: 1px solid var(--border-muted);
|
|
2632
2646
|
color: var(--fg-muted);
|
|
2633
2647
|
font-size: 11px;
|
|
2634
|
-
font-weight:
|
|
2635
|
-
letter-spacing: 0.
|
|
2648
|
+
font-weight: 600;
|
|
2649
|
+
letter-spacing: 0.06em;
|
|
2636
2650
|
text-transform: uppercase;
|
|
2637
2651
|
}
|
|
2638
2652
|
.gdp-markdown-toc ul {
|
|
@@ -2644,33 +2658,47 @@ table.d2h-diff-table tr.gdp-diff-line-target > td:first-child {
|
|
|
2644
2658
|
margin: 0;
|
|
2645
2659
|
}
|
|
2646
2660
|
.gdp-markdown-toc a {
|
|
2647
|
-
display:
|
|
2648
|
-
|
|
2649
|
-
|
|
2661
|
+
display: -webkit-box;
|
|
2662
|
+
min-height: 28px;
|
|
2663
|
+
padding: 5px 10px 5px 12px;
|
|
2664
|
+
border-left: 3px solid transparent;
|
|
2650
2665
|
border-radius: 5px;
|
|
2651
2666
|
color: var(--fg-muted);
|
|
2667
|
+
overflow: hidden;
|
|
2652
2668
|
overflow-wrap: anywhere;
|
|
2653
2669
|
text-decoration: none;
|
|
2670
|
+
-webkit-box-orient: vertical;
|
|
2671
|
+
-webkit-line-clamp: 2;
|
|
2672
|
+
transition:
|
|
2673
|
+
background-color 0.06s ease,
|
|
2674
|
+
border-color 0.06s ease,
|
|
2675
|
+
color 0.06s ease;
|
|
2654
2676
|
}
|
|
2655
2677
|
.gdp-markdown-toc .level-1 > a {
|
|
2656
2678
|
color: var(--fg);
|
|
2657
2679
|
font-weight: 600;
|
|
2658
2680
|
}
|
|
2659
2681
|
.gdp-markdown-toc .level-2 > a {
|
|
2660
|
-
padding-left:
|
|
2682
|
+
padding-left: 24px;
|
|
2661
2683
|
}
|
|
2662
2684
|
.gdp-markdown-toc .level-3 > a {
|
|
2663
|
-
padding-left:
|
|
2664
|
-
|
|
2685
|
+
padding-left: 38px;
|
|
2686
|
+
}
|
|
2687
|
+
.gdp-markdown-toc .level-4 > a {
|
|
2688
|
+
padding-left: 52px;
|
|
2665
2689
|
}
|
|
2666
2690
|
.gdp-markdown-toc a:hover {
|
|
2667
2691
|
background: var(--bg-mute);
|
|
2668
2692
|
color: var(--fg);
|
|
2669
2693
|
}
|
|
2694
|
+
.gdp-markdown-toc a:focus-visible {
|
|
2695
|
+
outline: 2px solid var(--accent);
|
|
2696
|
+
outline-offset: -2px;
|
|
2697
|
+
}
|
|
2670
2698
|
.gdp-markdown-toc a.active {
|
|
2671
2699
|
background: var(--accent-subtle);
|
|
2672
2700
|
border-left-color: var(--accent);
|
|
2673
|
-
color: var(--
|
|
2701
|
+
color: var(--fg);
|
|
2674
2702
|
font-weight: 600;
|
|
2675
2703
|
}
|
|
2676
2704
|
.gdp-markdown-preview h1,
|
|
@@ -2958,26 +2986,33 @@ body.gdp-file-detail-page.gdp-repo-blob-page #sidebar-resizer {
|
|
|
2958
2986
|
body.gdp-repo-page #sidebar-resizer {
|
|
2959
2987
|
display: block;
|
|
2960
2988
|
}
|
|
2961
|
-
body.gdp-file-detail-page.gdp-repo-blob-page .sb-title,
|
|
2962
|
-
body.gdp-file-detail-page.gdp-repo-blob-page #totals,
|
|
2963
|
-
body.gdp-repo-page .sb-title,
|
|
2964
|
-
body.gdp-repo-page #totals {
|
|
2965
|
-
display: none;
|
|
2966
|
-
}
|
|
2967
2989
|
body.gdp-repo-page .sb-head,
|
|
2968
2990
|
body.gdp-file-detail-page.gdp-repo-blob-page .sb-head {
|
|
2969
2991
|
display: grid;
|
|
2970
2992
|
grid-template:
|
|
2971
|
-
"toggle
|
|
2972
|
-
|
|
2973
|
-
|
|
2993
|
+
"toggle title totals ." auto
|
|
2994
|
+
"ref ref ref ref" auto
|
|
2995
|
+
"actions actions . view" auto
|
|
2996
|
+
"filter filter filter filter" auto
|
|
2997
|
+
/ 28px auto minmax(0, 1fr) auto;
|
|
2998
|
+
justify-content: stretch;
|
|
2974
2999
|
align-items: center;
|
|
2975
3000
|
gap: 8px;
|
|
3001
|
+
top: var(--global-header-h);
|
|
3002
|
+
z-index: 5;
|
|
2976
3003
|
}
|
|
2977
3004
|
body.gdp-repo-page .sb-head > #sidebar-toggle,
|
|
2978
3005
|
body.gdp-file-detail-page.gdp-repo-blob-page .sb-head > #sidebar-toggle {
|
|
2979
3006
|
grid-area: toggle;
|
|
2980
3007
|
}
|
|
3008
|
+
body.gdp-repo-page .sb-title,
|
|
3009
|
+
body.gdp-file-detail-page.gdp-repo-blob-page .sb-title {
|
|
3010
|
+
grid-area: title;
|
|
3011
|
+
}
|
|
3012
|
+
body.gdp-repo-page #totals,
|
|
3013
|
+
body.gdp-file-detail-page.gdp-repo-blob-page #totals {
|
|
3014
|
+
grid-area: totals;
|
|
3015
|
+
}
|
|
2981
3016
|
body.gdp-repo-page #repo-target-wrap,
|
|
2982
3017
|
body.gdp-file-detail-page.gdp-repo-blob-page #repo-target-wrap {
|
|
2983
3018
|
grid-area: ref;
|
|
@@ -2986,10 +3021,22 @@ body.gdp-file-detail-page.gdp-repo-blob-page #repo-target-wrap {
|
|
|
2986
3021
|
body.gdp-repo-page .sb-actions,
|
|
2987
3022
|
body.gdp-file-detail-page.gdp-repo-blob-page .sb-actions {
|
|
2988
3023
|
grid-area: actions;
|
|
3024
|
+
margin-left: 0;
|
|
3025
|
+
justify-self: start;
|
|
2989
3026
|
}
|
|
2990
3027
|
body.gdp-repo-page .sb-view-seg,
|
|
2991
3028
|
body.gdp-file-detail-page.gdp-repo-blob-page .sb-view-seg {
|
|
2992
3029
|
grid-area: view;
|
|
3030
|
+
margin-left: auto;
|
|
3031
|
+
}
|
|
3032
|
+
body.gdp-repo-page .sb-filter-wrap,
|
|
3033
|
+
body.gdp-file-detail-page.gdp-repo-blob-page .sb-filter-wrap {
|
|
3034
|
+
grid-area: filter;
|
|
3035
|
+
position: static;
|
|
3036
|
+
width: 100%;
|
|
3037
|
+
margin: 0;
|
|
3038
|
+
padding: 6px 0 0;
|
|
3039
|
+
border-bottom: 0;
|
|
2993
3040
|
}
|
|
2994
3041
|
body.gdp-file-detail-page {
|
|
2995
3042
|
--chrome-h: var(--global-header-h);
|