@youtyan/code-viewer 0.1.12 → 0.1.14
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 +825 -79
- package/web/index.html +1 -0
- package/web/style.css +218 -3
- package/web-src/routes.ts +16 -1
- package/web-src/server/git.ts +77 -57
- package/web-src/server/preview.ts +4 -1
- package/web-src/types.ts +1 -0
package/web/app.js
CHANGED
|
@@ -131,6 +131,80 @@
|
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
// web-src/focus-scope.ts
|
|
135
|
+
function isEditableKeyTarget(target) {
|
|
136
|
+
if (!target)
|
|
137
|
+
return false;
|
|
138
|
+
const tag = target.tagName;
|
|
139
|
+
return tag === "INPUT" || tag === "TEXTAREA" || target.closest('[contenteditable="true"]') != null;
|
|
140
|
+
}
|
|
141
|
+
function keymapScope(target) {
|
|
142
|
+
if (target?.closest("#content"))
|
|
143
|
+
return "main";
|
|
144
|
+
if (target?.closest("#sidebar"))
|
|
145
|
+
return "sidebar";
|
|
146
|
+
return "global";
|
|
147
|
+
}
|
|
148
|
+
function prepareKeyboardPanels(doc = document) {
|
|
149
|
+
const sidebar = doc.querySelector("#sidebar");
|
|
150
|
+
const content = doc.querySelector("#content");
|
|
151
|
+
if (sidebar)
|
|
152
|
+
sidebar.tabIndex = -1;
|
|
153
|
+
if (content)
|
|
154
|
+
content.tabIndex = -1;
|
|
155
|
+
}
|
|
156
|
+
function getPanelFocusScope(doc = document) {
|
|
157
|
+
const scope = doc.body?.dataset.focusScope;
|
|
158
|
+
return scope === "sidebar" || scope === "main" ? scope : null;
|
|
159
|
+
}
|
|
160
|
+
function setPanelFocusScope(scope, doc = document) {
|
|
161
|
+
if (!doc.body)
|
|
162
|
+
return;
|
|
163
|
+
if (scope)
|
|
164
|
+
doc.body.dataset.focusScope = scope;
|
|
165
|
+
else
|
|
166
|
+
delete doc.body.dataset.focusScope;
|
|
167
|
+
}
|
|
168
|
+
function restorePanelFocusScope(scope, doc = document) {
|
|
169
|
+
if (scope === "sidebar")
|
|
170
|
+
focusSidebarPanel(doc);
|
|
171
|
+
else if (scope === "main")
|
|
172
|
+
focusMainPanel(doc);
|
|
173
|
+
else
|
|
174
|
+
setPanelFocusScope(null, doc);
|
|
175
|
+
}
|
|
176
|
+
function focusSidebarPanel(doc = document) {
|
|
177
|
+
const active = doc.querySelector("#filelist li.active[data-path], #filelist .tree-dir.active[data-dirpath]");
|
|
178
|
+
const sidebar = doc.querySelector("#sidebar");
|
|
179
|
+
(active || sidebar)?.focus({ preventScroll: true });
|
|
180
|
+
setPanelFocusScope("sidebar", doc);
|
|
181
|
+
}
|
|
182
|
+
function focusMainPanel(doc = document) {
|
|
183
|
+
doc.querySelector("#content")?.focus({ preventScroll: true });
|
|
184
|
+
setPanelFocusScope("main", doc);
|
|
185
|
+
}
|
|
186
|
+
function findMainScrollTarget(doc = document) {
|
|
187
|
+
const active = doc.activeElement;
|
|
188
|
+
const activeScroller = active?.closest("#content .gdp-source-virtual-scroller");
|
|
189
|
+
if (activeScroller && activeScroller.offsetParent !== null)
|
|
190
|
+
return activeScroller;
|
|
191
|
+
const sourceScroller = doc.querySelector("#content .gdp-source-virtual-scroller");
|
|
192
|
+
if (sourceScroller && sourceScroller.offsetParent !== null)
|
|
193
|
+
return sourceScroller;
|
|
194
|
+
const content = doc.querySelector("#content");
|
|
195
|
+
if (!content || content.offsetParent === null)
|
|
196
|
+
return null;
|
|
197
|
+
const isScrollable = (item) => {
|
|
198
|
+
if (item.offsetParent === null)
|
|
199
|
+
return false;
|
|
200
|
+
const style = doc.defaultView?.getComputedStyle(item);
|
|
201
|
+
return !!style && /(auto|scroll)/.test(style.overflowY) && item.scrollHeight > item.clientHeight;
|
|
202
|
+
};
|
|
203
|
+
const preferred = Array.from(content.querySelectorAll(".gdp-source-viewer, .gdp-markdown-layout, .gdp-markdown-preview, .d2h-files-diff, .d2h-file-diff"));
|
|
204
|
+
const scrollable = preferred.find(isScrollable) || (isScrollable(content) ? content : null) || Array.from(content.querySelectorAll("*")).find(isScrollable);
|
|
205
|
+
return scrollable || doc.scrollingElement;
|
|
206
|
+
}
|
|
207
|
+
|
|
134
208
|
// web-src/fuzzy-search.ts
|
|
135
209
|
function basenameStart(path) {
|
|
136
210
|
const slash = path.lastIndexOf("/");
|
|
@@ -276,6 +350,77 @@
|
|
|
276
350
|
return rankFuzzyPaths(query, items).map((item) => ({ ...item, mode: "fuzzy" }));
|
|
277
351
|
}
|
|
278
352
|
|
|
353
|
+
// web-src/keymap.ts
|
|
354
|
+
var DEFAULT_KEY_BINDINGS = [
|
|
355
|
+
{ action: "open-file-palette", key: "k", ctrl: true, allowEditable: true, allowPaletteOpen: true },
|
|
356
|
+
{ action: "open-file-palette", key: "k", meta: true, allowEditable: true, allowPaletteOpen: true },
|
|
357
|
+
{ action: "open-grep-palette", key: "g", ctrl: true, allowEditable: true, allowPaletteOpen: true },
|
|
358
|
+
{ action: "open-grep-palette", key: "g", meta: true, allowEditable: true, allowPaletteOpen: true },
|
|
359
|
+
{ action: "focus-file-filter", key: "/" },
|
|
360
|
+
{ action: "focus-sidebar", key: "h", ctrl: true },
|
|
361
|
+
{ action: "focus-main", key: "l", ctrl: true },
|
|
362
|
+
{ action: "cancel-source-load", key: "escape", requires: { lightboxClosed: true } },
|
|
363
|
+
{ action: "open-sidebar-item", key: "enter", scope: "sidebar" },
|
|
364
|
+
{ action: "open-sidebar-item", key: "enter", scope: "global" },
|
|
365
|
+
{ action: "sidebar-next", key: "j", scope: "sidebar" },
|
|
366
|
+
{ action: "sidebar-next", key: "j", scope: "global" },
|
|
367
|
+
{ action: "sidebar-previous", key: "k", scope: "sidebar" },
|
|
368
|
+
{ action: "sidebar-previous", key: "k", scope: "global" },
|
|
369
|
+
{ action: "sidebar-page-down", key: "d", scope: "sidebar", ctrl: true },
|
|
370
|
+
{ action: "sidebar-page-down", key: "d", scope: "global", ctrl: true },
|
|
371
|
+
{ action: "sidebar-page-up", key: "u", scope: "sidebar", ctrl: true },
|
|
372
|
+
{ action: "sidebar-page-up", key: "u", scope: "global", ctrl: true },
|
|
373
|
+
{ action: "sidebar-expand", key: "l", scope: "sidebar" },
|
|
374
|
+
{ action: "sidebar-expand", key: "l", scope: "global" },
|
|
375
|
+
{ action: "sidebar-collapse", key: "h", scope: "sidebar" },
|
|
376
|
+
{ action: "sidebar-collapse", key: "h", scope: "global" },
|
|
377
|
+
{ action: "scroll-main-down", key: "j", scope: "main" },
|
|
378
|
+
{ action: "scroll-main-up", key: "k", scope: "main" },
|
|
379
|
+
{ action: "scroll-main-page-down", key: "d", scope: "main", ctrl: true },
|
|
380
|
+
{ action: "scroll-main-page-up", key: "u", scope: "main", ctrl: true },
|
|
381
|
+
{ action: "tab-preview", key: "p", scope: "main", pendingG: true },
|
|
382
|
+
{ action: "tab-code", key: "c", scope: "main", pendingG: true },
|
|
383
|
+
{ action: "goto-top", key: "g", pendingG: true },
|
|
384
|
+
{ action: "goto-bottom", key: "g", shift: true, pendingG: true },
|
|
385
|
+
{ action: "goto-bottom", key: "g", shift: true },
|
|
386
|
+
{ action: "start-g-sequence", key: "g", scope: "sidebar" },
|
|
387
|
+
{ action: "start-g-sequence", key: "g", scope: "main" },
|
|
388
|
+
{ action: "layout-unified", key: "u" },
|
|
389
|
+
{ action: "layout-split", key: "s" },
|
|
390
|
+
{ action: "toggle-theme", key: "t" }
|
|
391
|
+
];
|
|
392
|
+
function resolveKeymapAction(event, context) {
|
|
393
|
+
const key = event.key.toLowerCase();
|
|
394
|
+
if (context.composing)
|
|
395
|
+
return null;
|
|
396
|
+
for (const binding of DEFAULT_KEY_BINDINGS) {
|
|
397
|
+
if (binding.key !== key)
|
|
398
|
+
continue;
|
|
399
|
+
if (binding.requires?.lightboxClosed && context.lightboxOpen)
|
|
400
|
+
continue;
|
|
401
|
+
if (binding.scope && binding.scope !== context.scope)
|
|
402
|
+
continue;
|
|
403
|
+
if (!!binding.pendingG !== !!context.pendingG)
|
|
404
|
+
continue;
|
|
405
|
+
if (context.paletteOpen && !binding.allowPaletteOpen)
|
|
406
|
+
continue;
|
|
407
|
+
if (context.editable && !binding.allowEditable)
|
|
408
|
+
continue;
|
|
409
|
+
if (!!binding.ctrl !== !!event.ctrlKey)
|
|
410
|
+
continue;
|
|
411
|
+
if (!!binding.meta !== !!event.metaKey)
|
|
412
|
+
continue;
|
|
413
|
+
if (!!binding.alt !== !!event.altKey)
|
|
414
|
+
continue;
|
|
415
|
+
if (!!binding.shift !== !!event.shiftKey)
|
|
416
|
+
continue;
|
|
417
|
+
if (!binding.ctrl && !binding.meta && !binding.alt && !binding.shift && (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey))
|
|
418
|
+
continue;
|
|
419
|
+
return binding.action;
|
|
420
|
+
}
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
|
|
279
424
|
// web-src/search-palette.ts
|
|
280
425
|
var PALETTE_RESULT_LIMIT = 50;
|
|
281
426
|
function limitPaletteResults(items) {
|
|
@@ -369,6 +514,13 @@
|
|
|
369
514
|
return { screen: "unknown", reason: "missing-path", rawPathname: pathname, rawSearch: search, range };
|
|
370
515
|
return { screen: "file", path, ref, range, view: target ? "blob" : "detail", ...line ? { line } : {} };
|
|
371
516
|
}
|
|
517
|
+
case "/help":
|
|
518
|
+
return {
|
|
519
|
+
screen: "help",
|
|
520
|
+
range,
|
|
521
|
+
lang: params.get("lang") || "en",
|
|
522
|
+
section: params.get("section") || "keybindings"
|
|
523
|
+
};
|
|
372
524
|
default:
|
|
373
525
|
return { screen: "unknown", reason: "unknown-pathname", rawPathname: pathname, rawSearch: search, range };
|
|
374
526
|
}
|
|
@@ -391,6 +543,15 @@
|
|
|
391
543
|
return "/file?path=" + encodeURIComponent(route.path) + "&ref=" + encodeURIComponent(route.ref || "worktree") + "&from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree") + (route.line ? "&line=" + encodeURIComponent(formatLineTarget(route.line)) : "");
|
|
392
544
|
case "diff":
|
|
393
545
|
return "/todif?from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree") + (route.path ? "&path=" + encodeURIComponent(route.path) : "") + (route.line ? "&line=" + encodeURIComponent(formatLineTarget(route.line)) : "");
|
|
546
|
+
case "help": {
|
|
547
|
+
const params = new URLSearchParams;
|
|
548
|
+
if (route.lang && route.lang !== "en")
|
|
549
|
+
params.set("lang", route.lang);
|
|
550
|
+
if (route.section && route.section !== "keybindings")
|
|
551
|
+
params.set("section", route.section);
|
|
552
|
+
const qs = params.toString();
|
|
553
|
+
return "/help" + (qs ? "?" + qs : "");
|
|
554
|
+
}
|
|
394
555
|
case "unknown":
|
|
395
556
|
return "/todif?from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree");
|
|
396
557
|
default:
|
|
@@ -6184,7 +6345,29 @@
|
|
|
6184
6345
|
return markdown;
|
|
6185
6346
|
}
|
|
6186
6347
|
function renderMarkdownHtml(textValue, target, highlighter, signal) {
|
|
6187
|
-
|
|
6348
|
+
const md = createMarkdownIt(target, highlighter, signal);
|
|
6349
|
+
const frontmatter = splitYamlFrontmatter(textValue);
|
|
6350
|
+
if (!frontmatter)
|
|
6351
|
+
return md.render(textValue);
|
|
6352
|
+
return '<div class="gdp-markdown-frontmatter" data-gdp-frontmatter="yaml">' + md.render("```yaml\n" + frontmatter.yaml + "\n```\n") + "</div>" + md.render(frontmatter.body);
|
|
6353
|
+
}
|
|
6354
|
+
function splitYamlFrontmatter(textValue) {
|
|
6355
|
+
if (!textValue.startsWith(`---
|
|
6356
|
+
`) && !textValue.startsWith(`---\r
|
|
6357
|
+
`))
|
|
6358
|
+
return null;
|
|
6359
|
+
const newline2 = textValue.startsWith(`---\r
|
|
6360
|
+
`) ? `\r
|
|
6361
|
+
` : `
|
|
6362
|
+
`;
|
|
6363
|
+
const start = 3 + newline2.length;
|
|
6364
|
+
const closing = textValue.indexOf(newline2 + "---" + newline2, start);
|
|
6365
|
+
if (closing < 0)
|
|
6366
|
+
return null;
|
|
6367
|
+
return {
|
|
6368
|
+
yaml: textValue.slice(start, closing),
|
|
6369
|
+
body: textValue.slice(closing + newline2.length + 3 + newline2.length)
|
|
6370
|
+
};
|
|
6188
6371
|
}
|
|
6189
6372
|
async function loadMarkdownHighlighter() {
|
|
6190
6373
|
if (!shikiPromise) {
|
|
@@ -6581,6 +6764,179 @@
|
|
|
6581
6764
|
let REPO_SIDEBAR_REF = null;
|
|
6582
6765
|
let REPO_SIDEBAR_LOAD_REF = null;
|
|
6583
6766
|
let REPO_SIDEBAR_LOAD = null;
|
|
6767
|
+
let SIDEBAR_FILES = [];
|
|
6768
|
+
let SIDEBAR_ON_FILE_CLICK;
|
|
6769
|
+
let PENDING_G_SCOPE = null;
|
|
6770
|
+
let PENDING_G_UNTIL = 0;
|
|
6771
|
+
let SOURCE_CURSOR = null;
|
|
6772
|
+
const SOURCE_CURSOR_TOTALS = new Map;
|
|
6773
|
+
const HELP_LANGUAGES = ["en", "ja"];
|
|
6774
|
+
const HELP_SECTIONS = ["keybindings"];
|
|
6775
|
+
const HELP_CONTENT = {
|
|
6776
|
+
en: {
|
|
6777
|
+
languageLabel: "Language",
|
|
6778
|
+
title: "Help",
|
|
6779
|
+
sections: {
|
|
6780
|
+
keybindings: {
|
|
6781
|
+
nav: "Keybindings",
|
|
6782
|
+
title: "Keyboard Shortcuts",
|
|
6783
|
+
intro: "Use these shortcuts to move between panels and navigate files without leaving the keyboard.",
|
|
6784
|
+
groups: [
|
|
6785
|
+
{ title: "Global", rows: [["Ctrl+K", "Open file palette"], ["Ctrl+G", "Open grep palette"], ["/", "Focus file filter"], ["t", "Toggle theme"]] },
|
|
6786
|
+
{ title: "Panels", rows: [["Ctrl+H", "Focus sidebar"], ["Ctrl+L", "Focus main panel"]] },
|
|
6787
|
+
{ title: "Sidebar", rows: [["j / k", "Move selection down / up"], ["Ctrl+D / Ctrl+U", "Move selection by half a page"], ["gg / Shift+G", "Move to top / bottom"], ["Enter", "Open selected item"], ["h / l", "Collapse / expand directory"]] },
|
|
6788
|
+
{ title: "Main Panel", rows: [["j / k", "Move code cursor down / up"], ["Ctrl+D / Ctrl+U", "Move code cursor by half a page"], ["gg / Shift+G", "Move code cursor to top / bottom"], ["gp / gc", "Switch to Preview / Code tab"]] }
|
|
6789
|
+
]
|
|
6790
|
+
}
|
|
6791
|
+
}
|
|
6792
|
+
},
|
|
6793
|
+
ja: {
|
|
6794
|
+
languageLabel: "言語",
|
|
6795
|
+
title: "ヘルプ",
|
|
6796
|
+
sections: {
|
|
6797
|
+
keybindings: {
|
|
6798
|
+
nav: "キーバインド",
|
|
6799
|
+
title: "キーバインド",
|
|
6800
|
+
intro: "キーボードだけでパネル移動、ファイル選択、スクロールを行うためのショートカットです。",
|
|
6801
|
+
groups: [
|
|
6802
|
+
{ title: "グローバル", rows: [["Ctrl+K", "ファイルパレットを開く"], ["Ctrl+G", "grep パレットを開く"], ["/", "ファイルフィルターへフォーカス"], ["t", "テーマ切り替え"]] },
|
|
6803
|
+
{ title: "パネル", rows: [["Ctrl+H", "サイドバーへフォーカス"], ["Ctrl+L", "メインパネルへフォーカス"]] },
|
|
6804
|
+
{ title: "サイドバー", rows: [["j / k", "選択を下 / 上へ移動"], ["Ctrl+D / Ctrl+U", "半ページ分選択を移動"], ["gg / Shift+G", "先頭 / 末尾へ移動"], ["Enter", "選択項目を開く"], ["h / l", "ディレクトリを閉じる / 開く"]] },
|
|
6805
|
+
{ title: "メインパネル", rows: [["j / k", "コードカーソルを下 / 上へ移動"], ["Ctrl+D / Ctrl+U", "コードカーソルを半ページ分移動"], ["gg / Shift+G", "コードカーソルを先頭 / 末尾へ移動"], ["gp / gc", "Preview / Code タブへ切り替え"]] }
|
|
6806
|
+
]
|
|
6807
|
+
}
|
|
6808
|
+
}
|
|
6809
|
+
}
|
|
6810
|
+
};
|
|
6811
|
+
function sourceLineScrollAmount() {
|
|
6812
|
+
const virtualRow = Array.from(document.querySelectorAll("#content .gdp-source-virtual-row")).find((item) => item.offsetParent !== null);
|
|
6813
|
+
if (virtualRow)
|
|
6814
|
+
return virtualRow.getBoundingClientRect().height || VIRTUAL_SOURCE_ROW_HEIGHT;
|
|
6815
|
+
const sourceRow = Array.from(document.querySelectorAll("#content .gdp-source-table tr")).find((item) => item.offsetParent !== null);
|
|
6816
|
+
if (sourceRow)
|
|
6817
|
+
return sourceRow.getBoundingClientRect().height || 20;
|
|
6818
|
+
const preview = document.querySelector("#content .gdp-markdown-preview:not([hidden])");
|
|
6819
|
+
const lineHeight = Number.parseFloat(getComputedStyle(preview || document.body).lineHeight);
|
|
6820
|
+
return Number.isFinite(lineHeight) && lineHeight > 0 ? lineHeight : 20;
|
|
6821
|
+
}
|
|
6822
|
+
function hasVisibleSourceCodeSurface() {
|
|
6823
|
+
return Array.from(document.querySelectorAll("#content .gdp-source-virtual-scroller, #content .gdp-source-table")).some((item) => item.offsetParent !== null);
|
|
6824
|
+
}
|
|
6825
|
+
function sourceCursorKey(target) {
|
|
6826
|
+
return target.ref + "\x00" + target.path;
|
|
6827
|
+
}
|
|
6828
|
+
function sourceCursorMatches(target, line) {
|
|
6829
|
+
return !!SOURCE_CURSOR && sourceTargetsEqual(SOURCE_CURSOR.target, target) && SOURCE_CURSOR.line === line;
|
|
6830
|
+
}
|
|
6831
|
+
function syncSourceCursorRows(target) {
|
|
6832
|
+
document.querySelectorAll("#content [data-line]").forEach((row) => {
|
|
6833
|
+
const line = Number(row.dataset.line || "0");
|
|
6834
|
+
row.classList.toggle("gdp-source-cursor", sourceCursorMatches(target, line));
|
|
6835
|
+
});
|
|
6836
|
+
}
|
|
6837
|
+
function visibleSourceLineFallback() {
|
|
6838
|
+
const scroller = findMainScrollTarget();
|
|
6839
|
+
if (scroller)
|
|
6840
|
+
return Math.max(1, Math.floor(scroller.scrollTop / VIRTUAL_SOURCE_ROW_HEIGHT) + 1);
|
|
6841
|
+
const rows = $$("#content .gdp-source-table tr[data-line]");
|
|
6842
|
+
const contentTop = document.querySelector("#content")?.getBoundingClientRect().top ?? 0;
|
|
6843
|
+
const row = rows.find((item) => item.getBoundingClientRect().bottom >= Math.max(0, contentTop));
|
|
6844
|
+
return Math.max(1, Number(row?.dataset.line || "1"));
|
|
6845
|
+
}
|
|
6846
|
+
function ensureSourceCursor(target) {
|
|
6847
|
+
if (SOURCE_CURSOR && sourceTargetsEqual(SOURCE_CURSOR.target, target))
|
|
6848
|
+
return SOURCE_CURSOR;
|
|
6849
|
+
const routeLine = lineTargetStart(currentSourceLineTarget(target));
|
|
6850
|
+
SOURCE_CURSOR = { target, line: routeLine || visibleSourceLineFallback() };
|
|
6851
|
+
syncSourceCursorRows(target);
|
|
6852
|
+
return SOURCE_CURSOR;
|
|
6853
|
+
}
|
|
6854
|
+
function resetSourceCursorForTarget(target, totalLines) {
|
|
6855
|
+
const routeLine = lineTargetStart(currentSourceLineTarget(target));
|
|
6856
|
+
SOURCE_CURSOR = { target, line: Math.max(1, Math.min(totalLines, routeLine || 1)) };
|
|
6857
|
+
}
|
|
6858
|
+
function scrollSourceCursorIntoView(cursor, edge = "nearest") {
|
|
6859
|
+
const scroller = findMainScrollTarget();
|
|
6860
|
+
if (scroller) {
|
|
6861
|
+
const top = (cursor.line - 1) * VIRTUAL_SOURCE_ROW_HEIGHT;
|
|
6862
|
+
const bottom = top + VIRTUAL_SOURCE_ROW_HEIGHT;
|
|
6863
|
+
const before = scroller.scrollTop;
|
|
6864
|
+
if (edge === "center")
|
|
6865
|
+
scroller.scrollTop = Math.max(0, top - Math.round(scroller.clientHeight / 2));
|
|
6866
|
+
else if (top < scroller.scrollTop)
|
|
6867
|
+
scroller.scrollTop = top;
|
|
6868
|
+
else if (bottom > scroller.scrollTop + scroller.clientHeight)
|
|
6869
|
+
scroller.scrollTop = bottom - scroller.clientHeight;
|
|
6870
|
+
if (scroller.scrollTop !== before)
|
|
6871
|
+
scroller.dispatchEvent(new Event("scroll"));
|
|
6872
|
+
scroller.__gdpRenderVirtualSource?.();
|
|
6873
|
+
syncSourceCursorRows(cursor.target);
|
|
6874
|
+
return;
|
|
6875
|
+
}
|
|
6876
|
+
document.querySelector('#content [data-line="' + cursor.line + '"]')?.scrollIntoView({ block: edge });
|
|
6877
|
+
}
|
|
6878
|
+
function moveSourceCursor(direction, unit, edge) {
|
|
6879
|
+
if (!hasVisibleSourceCodeSurface())
|
|
6880
|
+
return false;
|
|
6881
|
+
const target = sourceTargetFromRoute();
|
|
6882
|
+
if (!target)
|
|
6883
|
+
return false;
|
|
6884
|
+
const total = SOURCE_CURSOR_TOTALS.get(sourceCursorKey(target));
|
|
6885
|
+
if (!total)
|
|
6886
|
+
return false;
|
|
6887
|
+
const cursor = ensureSourceCursor(target);
|
|
6888
|
+
if (unit === "edge") {
|
|
6889
|
+
cursor.line = edge === "bottom" ? total : 1;
|
|
6890
|
+
syncSourceCursorRows(target);
|
|
6891
|
+
scrollSourceCursorIntoView(cursor, "center");
|
|
6892
|
+
return true;
|
|
6893
|
+
}
|
|
6894
|
+
const pageRows = Math.max(1, Math.floor((findMainScrollTarget()?.clientHeight || window.innerHeight) * 0.55 / (sourceLineScrollAmount() || VIRTUAL_SOURCE_ROW_HEIGHT)));
|
|
6895
|
+
const delta = unit === "page" ? pageRows : 1;
|
|
6896
|
+
cursor.line = Math.max(1, Math.min(total, cursor.line + direction * delta));
|
|
6897
|
+
syncSourceCursorRows(target);
|
|
6898
|
+
scrollSourceCursorIntoView(cursor);
|
|
6899
|
+
return true;
|
|
6900
|
+
}
|
|
6901
|
+
function scrollMainPanel(direction, repeated = false, unit = "line") {
|
|
6902
|
+
if (moveSourceCursor(direction, unit))
|
|
6903
|
+
return;
|
|
6904
|
+
const target = findMainScrollTarget();
|
|
6905
|
+
const viewportHeight = target?.clientHeight || document.scrollingElement?.clientHeight || window.innerHeight;
|
|
6906
|
+
const top = direction * (unit === "line" ? Math.round(sourceLineScrollAmount() || 32) : Math.round(viewportHeight * 0.55));
|
|
6907
|
+
const behavior = repeated ? "auto" : "smooth";
|
|
6908
|
+
if (target)
|
|
6909
|
+
target.scrollBy({ top, behavior });
|
|
6910
|
+
else
|
|
6911
|
+
window.scrollBy({ top, behavior });
|
|
6912
|
+
}
|
|
6913
|
+
function scrollMainToEdge(edge) {
|
|
6914
|
+
if (moveSourceCursor(edge === "bottom" ? 1 : -1, "edge", edge))
|
|
6915
|
+
return;
|
|
6916
|
+
const target = findMainScrollTarget();
|
|
6917
|
+
if (target) {
|
|
6918
|
+
target.scrollTo({ top: edge === "top" ? 0 : target.scrollHeight, behavior: "auto" });
|
|
6919
|
+
return;
|
|
6920
|
+
}
|
|
6921
|
+
const top = edge === "top" ? 0 : Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
|
|
6922
|
+
window.scrollTo({ top, behavior: "auto" });
|
|
6923
|
+
}
|
|
6924
|
+
function switchSourceTab(tab) {
|
|
6925
|
+
const tabs = document.querySelector("#content .gdp-source-tabs");
|
|
6926
|
+
if (!tabs)
|
|
6927
|
+
return false;
|
|
6928
|
+
const button = tabs.querySelector('button[data-source-tab="' + tab + '"]');
|
|
6929
|
+
if (!button || button.hidden || button.disabled)
|
|
6930
|
+
return false;
|
|
6931
|
+
button.click();
|
|
6932
|
+
focusMainPanel();
|
|
6933
|
+
return true;
|
|
6934
|
+
}
|
|
6935
|
+
function isFocusableClickTarget(target) {
|
|
6936
|
+
if (!(target instanceof Element))
|
|
6937
|
+
return false;
|
|
6938
|
+
return !!target.closest('a, button, input, textarea, select, summary, [tabindex]:not([tabindex="-1"]), [contenteditable="true"]');
|
|
6939
|
+
}
|
|
6584
6940
|
function invalidateRepoSidebar() {
|
|
6585
6941
|
REPO_SIDEBAR_REF = null;
|
|
6586
6942
|
REPO_SIDEBAR_LOAD_REF = null;
|
|
@@ -6885,8 +7241,10 @@
|
|
|
6885
7241
|
}
|
|
6886
7242
|
if (f2.type === "tree") {
|
|
6887
7243
|
node.explicit = true;
|
|
6888
|
-
if (f2.children_omitted === true)
|
|
7244
|
+
if (f2.children_omitted === true) {
|
|
6889
7245
|
node.children_omitted = true;
|
|
7246
|
+
node.children_omitted_reason = f2.children_omitted_reason;
|
|
7247
|
+
}
|
|
6890
7248
|
continue;
|
|
6891
7249
|
}
|
|
6892
7250
|
node.files.push(f2);
|
|
@@ -6923,17 +7281,24 @@
|
|
|
6923
7281
|
const dir = item.dir;
|
|
6924
7282
|
const li = document.createElement("li");
|
|
6925
7283
|
li.className = "tree-dir";
|
|
7284
|
+
li.tabIndex = -1;
|
|
6926
7285
|
li.dataset.dirpath = dir.path;
|
|
6927
7286
|
if (dir.explicit)
|
|
6928
7287
|
li.dataset.explicit = "true";
|
|
6929
7288
|
if (dir.children_omitted) {
|
|
6930
7289
|
li.classList.add("children-omitted");
|
|
6931
|
-
li.
|
|
7290
|
+
li.classList.add(dir.children_omitted_reason === "ignored" ? "children-omitted-ignored" : "children-omitted-internal");
|
|
7291
|
+
li.title = dir.children_omitted_reason === "ignored" ? "Ignored directory: open the detail pane to browse its contents" : "Internal Git metadata is not browsed";
|
|
6932
7292
|
}
|
|
6933
7293
|
li.style.setProperty("--lvl-pad", 12 + depth * 14 + "px");
|
|
6934
7294
|
const chev = document.createElement("span");
|
|
6935
|
-
|
|
6936
|
-
|
|
7295
|
+
if (dir.children_omitted) {
|
|
7296
|
+
chev.className = "chev-spacer";
|
|
7297
|
+
chev.setAttribute("aria-hidden", "true");
|
|
7298
|
+
} else {
|
|
7299
|
+
chev.className = "chev";
|
|
7300
|
+
setChevronIcon(chev);
|
|
7301
|
+
}
|
|
6937
7302
|
li.appendChild(chev);
|
|
6938
7303
|
const dirIcon = document.createElement("span");
|
|
6939
7304
|
dirIcon.className = "dir-icon";
|
|
@@ -6947,9 +7312,9 @@
|
|
|
6947
7312
|
label.appendChild(dn);
|
|
6948
7313
|
if (dir.children_omitted) {
|
|
6949
7314
|
const omitted = document.createElement("span");
|
|
6950
|
-
omitted.className = "dir-omitted";
|
|
6951
|
-
omitted.textContent = "
|
|
6952
|
-
omitted.title = "
|
|
7315
|
+
omitted.className = "dir-omitted " + (dir.children_omitted_reason === "ignored" ? "dir-omitted-ignored" : "dir-omitted-internal");
|
|
7316
|
+
omitted.textContent = dir.children_omitted_reason === "ignored" ? "ignored" : "private";
|
|
7317
|
+
omitted.title = dir.children_omitted_reason === "ignored" ? "Tree expansion is skipped, but the directory detail can be opened" : "This directory cannot be opened from the browser";
|
|
6953
7318
|
label.appendChild(omitted);
|
|
6954
7319
|
}
|
|
6955
7320
|
li.appendChild(label);
|
|
@@ -6974,12 +7339,25 @@
|
|
|
6974
7339
|
STATE.collapsedDirs.delete(dir.path);
|
|
6975
7340
|
localStorage.setItem("gdp:collapsed-dirs", JSON.stringify([...STATE.collapsedDirs]));
|
|
6976
7341
|
};
|
|
6977
|
-
|
|
6978
|
-
|
|
7342
|
+
if (!dir.children_omitted) {
|
|
7343
|
+
chev.addEventListener("click", toggleDir);
|
|
7344
|
+
dirIcon.addEventListener("click", toggleDir);
|
|
7345
|
+
}
|
|
6979
7346
|
if (onFileClick) {
|
|
6980
7347
|
li.addEventListener("click", (e2) => {
|
|
6981
7348
|
e2.stopPropagation();
|
|
6982
|
-
|
|
7349
|
+
if (dir.children_omitted_reason === "internal")
|
|
7350
|
+
return;
|
|
7351
|
+
if (dir.children_omitted_reason !== "internal") {
|
|
7352
|
+
onFileClick({
|
|
7353
|
+
path: dir.path,
|
|
7354
|
+
display_path: dir.path,
|
|
7355
|
+
type: "tree",
|
|
7356
|
+
children_omitted: dir.children_omitted,
|
|
7357
|
+
children_omitted_reason: dir.children_omitted_reason
|
|
7358
|
+
});
|
|
7359
|
+
}
|
|
7360
|
+
focusSidebarPanel();
|
|
6983
7361
|
});
|
|
6984
7362
|
} else {
|
|
6985
7363
|
li.addEventListener("click", toggleDir);
|
|
@@ -6990,6 +7368,7 @@
|
|
|
6990
7368
|
const f2 = item.file;
|
|
6991
7369
|
const li = document.createElement("li");
|
|
6992
7370
|
li.className = "tree-file";
|
|
7371
|
+
li.tabIndex = -1;
|
|
6993
7372
|
li.dataset.path = f2.path;
|
|
6994
7373
|
li.classList.toggle("viewed", !onFileClick && STATE.viewedFiles.has(f2.path));
|
|
6995
7374
|
li.style.setProperty("--lvl-pad", 12 + depth * 14 + "px");
|
|
@@ -7014,6 +7393,7 @@
|
|
|
7014
7393
|
onFileClick(f2);
|
|
7015
7394
|
else
|
|
7016
7395
|
scrollToFile(f2.path);
|
|
7396
|
+
focusSidebarPanel();
|
|
7017
7397
|
});
|
|
7018
7398
|
if (!onFileClick)
|
|
7019
7399
|
li.addEventListener("mouseenter", () => prefetchByPath(f2.path), { passive: true });
|
|
@@ -7024,6 +7404,7 @@
|
|
|
7024
7404
|
function renderFlat(files, ul, onFileClick) {
|
|
7025
7405
|
files.forEach((f2, i2) => {
|
|
7026
7406
|
const li = document.createElement("li");
|
|
7407
|
+
li.tabIndex = -1;
|
|
7027
7408
|
li.dataset.index = String(i2);
|
|
7028
7409
|
li.dataset.path = f2.path;
|
|
7029
7410
|
li.classList.toggle("viewed", !onFileClick && STATE.viewedFiles.has(f2.path));
|
|
@@ -7045,6 +7426,7 @@
|
|
|
7045
7426
|
onFileClick(f2);
|
|
7046
7427
|
else
|
|
7047
7428
|
scrollToFile(f2.path);
|
|
7429
|
+
focusSidebarPanel();
|
|
7048
7430
|
});
|
|
7049
7431
|
if (!onFileClick)
|
|
7050
7432
|
li.addEventListener("mouseenter", () => prefetchByPath(f2.path), { passive: true });
|
|
@@ -7056,6 +7438,8 @@
|
|
|
7056
7438
|
ul.innerHTML = "";
|
|
7057
7439
|
ul.classList.toggle("tree", STATE.sbView === "tree");
|
|
7058
7440
|
STATE.files = files;
|
|
7441
|
+
SIDEBAR_FILES = files;
|
|
7442
|
+
SIDEBAR_ON_FILE_CLICK = onFileClick;
|
|
7059
7443
|
if (!onFileClick)
|
|
7060
7444
|
REPO_SIDEBAR_REF = null;
|
|
7061
7445
|
if (STATE.sbView === "tree") {
|
|
@@ -7190,13 +7574,43 @@
|
|
|
7190
7574
|
card.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
7191
7575
|
}
|
|
7192
7576
|
}
|
|
7193
|
-
function
|
|
7577
|
+
function sidebarAncestorDirs(path) {
|
|
7578
|
+
const parts = path.split("/").filter(Boolean);
|
|
7579
|
+
const dirs = [];
|
|
7580
|
+
for (let i2 = 1;i2 < parts.length; i2++)
|
|
7581
|
+
dirs.push(parts.slice(0, i2).join("/"));
|
|
7582
|
+
return dirs;
|
|
7583
|
+
}
|
|
7584
|
+
function expandSidebarAncestors(path) {
|
|
7585
|
+
if (STATE.sbView !== "tree")
|
|
7586
|
+
return;
|
|
7587
|
+
let changed = false;
|
|
7588
|
+
for (const dir of sidebarAncestorDirs(path)) {
|
|
7589
|
+
if (STATE.collapsedDirs.delete(dir))
|
|
7590
|
+
changed = true;
|
|
7591
|
+
const row = document.querySelector('#filelist .tree-dir[data-dirpath="' + CSS.escape(dir) + '"]');
|
|
7592
|
+
row?.classList.remove("collapsed");
|
|
7593
|
+
const icon = row?.querySelector(".dir-icon");
|
|
7594
|
+
if (icon)
|
|
7595
|
+
setFolderIcon(icon, false);
|
|
7596
|
+
}
|
|
7597
|
+
if (changed)
|
|
7598
|
+
localStorage.setItem("gdp:collapsed-dirs", JSON.stringify([...STATE.collapsedDirs]));
|
|
7599
|
+
}
|
|
7600
|
+
function markActive(path, options = {}) {
|
|
7194
7601
|
STATE.activeFile = path;
|
|
7602
|
+
if (options.reveal && STATE.sbView === "tree")
|
|
7603
|
+
expandSidebarAncestors(path);
|
|
7195
7604
|
$$("#filelist li").forEach((li) => {
|
|
7196
7605
|
const itemPath = li.dataset.path || li.dataset.dirpath;
|
|
7197
7606
|
if (itemPath)
|
|
7198
7607
|
li.classList.toggle("active", itemPath === path);
|
|
7199
7608
|
});
|
|
7609
|
+
if (options.reveal) {
|
|
7610
|
+
const active = document.querySelector("#filelist li.active[data-path], #filelist .tree-dir.active[data-dirpath]");
|
|
7611
|
+
if (active)
|
|
7612
|
+
requestAnimationFrame(() => scrollSidebarItemIntoView(active));
|
|
7613
|
+
}
|
|
7200
7614
|
}
|
|
7201
7615
|
function applyViewedState() {
|
|
7202
7616
|
$$("#filelist li[data-path]").forEach((li) => {
|
|
@@ -7313,6 +7727,12 @@
|
|
|
7313
7727
|
function repoFileTargetFromRoute() {
|
|
7314
7728
|
return STATE.route.screen === "file" && STATE.route.view === "blob" ? STATE.route.ref : null;
|
|
7315
7729
|
}
|
|
7730
|
+
function helpLanguageFromRoute() {
|
|
7731
|
+
return STATE.route.screen === "help" && HELP_LANGUAGES.includes(STATE.route.lang) ? STATE.route.lang : "en";
|
|
7732
|
+
}
|
|
7733
|
+
function helpSectionFromRoute() {
|
|
7734
|
+
return STATE.route.screen === "help" && HELP_SECTIONS.includes(STATE.route.section) ? STATE.route.section : "keybindings";
|
|
7735
|
+
}
|
|
7316
7736
|
function setRoute(route, replace2 = false) {
|
|
7317
7737
|
const nextRoute = route.screen === "unknown" ? { screen: "diff", range: route.range } : route;
|
|
7318
7738
|
STATE.route = nextRoute;
|
|
@@ -7333,6 +7753,7 @@
|
|
|
7333
7753
|
document.body.classList.toggle("gdp-file-detail-page", STATE.route.screen === "file");
|
|
7334
7754
|
document.body.classList.toggle("gdp-repo-blob-page", STATE.route.screen === "file" && STATE.route.view === "blob");
|
|
7335
7755
|
document.body.classList.toggle("gdp-repo-page", STATE.route.screen === "repo");
|
|
7756
|
+
document.body.classList.toggle("gdp-help-page", STATE.route.screen === "help");
|
|
7336
7757
|
syncRepoTargetInput(repoFileTargetFromRoute() || "worktree");
|
|
7337
7758
|
}
|
|
7338
7759
|
function syncHeaderMenu() {
|
|
@@ -7347,12 +7768,104 @@
|
|
|
7347
7768
|
if (link2.dataset.route === "diff") {
|
|
7348
7769
|
link2.href = buildRoute({ screen: "diff", range: currentRange() });
|
|
7349
7770
|
}
|
|
7771
|
+
if (link2.dataset.route === "help") {
|
|
7772
|
+
link2.href = buildRoute({ screen: "help", lang: helpLanguageFromRoute(), section: helpSectionFromRoute(), range: currentRange() });
|
|
7773
|
+
}
|
|
7350
7774
|
});
|
|
7351
7775
|
}
|
|
7352
7776
|
function removeStandaloneSource() {
|
|
7353
7777
|
document.querySelectorAll(".gdp-standalone-source").forEach((el) => el.remove());
|
|
7354
7778
|
document.querySelectorAll(".gdp-repo-blob-layout").forEach((el) => el.remove());
|
|
7355
7779
|
}
|
|
7780
|
+
function renderHelpPage() {
|
|
7781
|
+
cancelActiveSourceLoad("navigation");
|
|
7782
|
+
removeStandaloneSource();
|
|
7783
|
+
LOAD_QUEUE.length = 0;
|
|
7784
|
+
const target = $("#diff");
|
|
7785
|
+
const empty = $("#empty");
|
|
7786
|
+
empty.classList.add("hidden");
|
|
7787
|
+
$("#meta").textContent = "";
|
|
7788
|
+
$("#totals").textContent = "";
|
|
7789
|
+
$("#filelist").textContent = "";
|
|
7790
|
+
const lang = helpLanguageFromRoute();
|
|
7791
|
+
const section = helpSectionFromRoute();
|
|
7792
|
+
const content = HELP_CONTENT[lang];
|
|
7793
|
+
const sectionContent = content.sections[section];
|
|
7794
|
+
const shell = document.createElement("section");
|
|
7795
|
+
shell.className = "gdp-help-shell";
|
|
7796
|
+
const header = document.createElement("header");
|
|
7797
|
+
header.className = "gdp-help-header";
|
|
7798
|
+
const title = document.createElement("h1");
|
|
7799
|
+
title.textContent = content.title;
|
|
7800
|
+
const langSelect = document.createElement("select");
|
|
7801
|
+
langSelect.className = "gdp-help-language";
|
|
7802
|
+
langSelect.setAttribute("aria-label", content.languageLabel);
|
|
7803
|
+
HELP_LANGUAGES.forEach((optionLang) => {
|
|
7804
|
+
const option = document.createElement("option");
|
|
7805
|
+
option.value = optionLang;
|
|
7806
|
+
option.textContent = optionLang.toUpperCase();
|
|
7807
|
+
option.selected = optionLang === lang;
|
|
7808
|
+
langSelect.appendChild(option);
|
|
7809
|
+
});
|
|
7810
|
+
langSelect.addEventListener("change", () => {
|
|
7811
|
+
setRoute({ screen: "help", lang: langSelect.value, section, range: currentRange() });
|
|
7812
|
+
setPageMode();
|
|
7813
|
+
renderHelpPage();
|
|
7814
|
+
syncHeaderMenu();
|
|
7815
|
+
});
|
|
7816
|
+
header.append(title, langSelect);
|
|
7817
|
+
const layout = document.createElement("div");
|
|
7818
|
+
layout.className = "gdp-help-layout";
|
|
7819
|
+
const helpNav = document.createElement("nav");
|
|
7820
|
+
helpNav.className = "gdp-help-nav";
|
|
7821
|
+
HELP_SECTIONS.forEach((helpSection) => {
|
|
7822
|
+
const button = document.createElement("button");
|
|
7823
|
+
button.type = "button";
|
|
7824
|
+
button.className = helpSection === section ? "active" : "";
|
|
7825
|
+
button.textContent = content.sections[helpSection].nav;
|
|
7826
|
+
button.addEventListener("click", () => {
|
|
7827
|
+
setRoute({ screen: "help", lang, section: helpSection, range: currentRange() });
|
|
7828
|
+
renderHelpPage();
|
|
7829
|
+
syncHeaderMenu();
|
|
7830
|
+
});
|
|
7831
|
+
helpNav.appendChild(button);
|
|
7832
|
+
});
|
|
7833
|
+
const article = document.createElement("article");
|
|
7834
|
+
article.className = "gdp-help-content";
|
|
7835
|
+
const h2 = document.createElement("h2");
|
|
7836
|
+
h2.textContent = sectionContent.title;
|
|
7837
|
+
const intro = document.createElement("p");
|
|
7838
|
+
intro.textContent = sectionContent.intro;
|
|
7839
|
+
article.append(h2, intro);
|
|
7840
|
+
sectionContent.groups.forEach((group) => {
|
|
7841
|
+
const groupSection = document.createElement("section");
|
|
7842
|
+
groupSection.className = "gdp-help-group";
|
|
7843
|
+
const groupTitle = document.createElement("h3");
|
|
7844
|
+
groupTitle.textContent = group.title;
|
|
7845
|
+
const table2 = document.createElement("table");
|
|
7846
|
+
group.rows.forEach(([keys, description]) => {
|
|
7847
|
+
const tr = document.createElement("tr");
|
|
7848
|
+
const keyCell = document.createElement("th");
|
|
7849
|
+
keyCell.scope = "row";
|
|
7850
|
+
keys.split(" / ").forEach((key, index) => {
|
|
7851
|
+
if (index > 0)
|
|
7852
|
+
keyCell.append(" / ");
|
|
7853
|
+
const kbd = document.createElement("kbd");
|
|
7854
|
+
kbd.textContent = key;
|
|
7855
|
+
keyCell.appendChild(kbd);
|
|
7856
|
+
});
|
|
7857
|
+
const desc = document.createElement("td");
|
|
7858
|
+
desc.textContent = description;
|
|
7859
|
+
tr.append(keyCell, desc);
|
|
7860
|
+
table2.appendChild(tr);
|
|
7861
|
+
});
|
|
7862
|
+
groupSection.append(groupTitle, table2);
|
|
7863
|
+
article.appendChild(groupSection);
|
|
7864
|
+
});
|
|
7865
|
+
layout.append(helpNav, article);
|
|
7866
|
+
shell.append(header, layout);
|
|
7867
|
+
target.replaceChildren(shell);
|
|
7868
|
+
}
|
|
7356
7869
|
function renderShell(meta) {
|
|
7357
7870
|
const newFiles = meta.files || [];
|
|
7358
7871
|
STATE.files = newFiles;
|
|
@@ -7780,7 +8293,8 @@
|
|
|
7780
8293
|
path: entry.path,
|
|
7781
8294
|
display_path: entry.path,
|
|
7782
8295
|
type: entry.type,
|
|
7783
|
-
children_omitted: entry.children_omitted
|
|
8296
|
+
children_omitted: entry.children_omitted,
|
|
8297
|
+
children_omitted_reason: entry.children_omitted_reason
|
|
7784
8298
|
}));
|
|
7785
8299
|
renderSidebar(files, (file) => {
|
|
7786
8300
|
if (file.type === "tree") {
|
|
@@ -7807,7 +8321,7 @@
|
|
|
7807
8321
|
return load2;
|
|
7808
8322
|
}
|
|
7809
8323
|
function activateRepoSidebarPath(currentPath) {
|
|
7810
|
-
markActive(currentPath);
|
|
8324
|
+
markActive(currentPath, { reveal: true });
|
|
7811
8325
|
applyFilter();
|
|
7812
8326
|
}
|
|
7813
8327
|
function createPlaceholder(f2) {
|
|
@@ -8754,6 +9268,8 @@
|
|
|
8754
9268
|
function sourceDisplayKind(path) {
|
|
8755
9269
|
if (isVideo(path))
|
|
8756
9270
|
return "video";
|
|
9271
|
+
if (isAudio(path))
|
|
9272
|
+
return "audio";
|
|
8757
9273
|
if (isImage(path))
|
|
8758
9274
|
return "image";
|
|
8759
9275
|
if (/\.pdf$/i.test(path))
|
|
@@ -8800,10 +9316,28 @@
|
|
|
8800
9316
|
return "MP4 video";
|
|
8801
9317
|
if (ext === "webm")
|
|
8802
9318
|
return "WebM video";
|
|
9319
|
+
if (ext === "mp3")
|
|
9320
|
+
return "MP3 audio";
|
|
9321
|
+
if (ext === "wav")
|
|
9322
|
+
return "WAV audio";
|
|
9323
|
+
if (ext === "ogg")
|
|
9324
|
+
return "Ogg audio";
|
|
9325
|
+
if (ext === "flac")
|
|
9326
|
+
return "FLAC audio";
|
|
9327
|
+
if (ext === "m4a")
|
|
9328
|
+
return "M4A audio";
|
|
9329
|
+
if (ext === "aac")
|
|
9330
|
+
return "AAC audio";
|
|
9331
|
+
if (ext === "opus")
|
|
9332
|
+
return "Opus audio";
|
|
9333
|
+
if (ext === "mid" || ext === "midi")
|
|
9334
|
+
return "MIDI file";
|
|
8803
9335
|
if (mime?.startsWith("image/"))
|
|
8804
9336
|
return "Image";
|
|
8805
9337
|
if (mime?.startsWith("video/"))
|
|
8806
9338
|
return "Video";
|
|
9339
|
+
if (mime?.startsWith("audio/"))
|
|
9340
|
+
return "Audio";
|
|
8807
9341
|
if (mime === "application/pdf")
|
|
8808
9342
|
return "PDF document";
|
|
8809
9343
|
if (fallback === "unsupported file")
|
|
@@ -8842,11 +9376,35 @@
|
|
|
8842
9376
|
});
|
|
8843
9377
|
return info;
|
|
8844
9378
|
}
|
|
8845
|
-
function
|
|
9379
|
+
function createSourceCopyButton(textValue) {
|
|
9380
|
+
const copy = document.createElement("button");
|
|
9381
|
+
copy.type = "button";
|
|
9382
|
+
copy.className = "gdp-file-header-icon gdp-copy-source";
|
|
9383
|
+
copy.title = "Copy source";
|
|
9384
|
+
copy.setAttribute("aria-label", "Copy source");
|
|
9385
|
+
copy.innerHTML = iconSvg("octicon-copy", COPY_16_PATHS);
|
|
9386
|
+
copy.addEventListener("click", async () => {
|
|
9387
|
+
try {
|
|
9388
|
+
await navigator.clipboard.writeText(textValue);
|
|
9389
|
+
copy.classList.add("copied");
|
|
9390
|
+
setTimeout(() => {
|
|
9391
|
+
copy.classList.remove("copied");
|
|
9392
|
+
}, 1200);
|
|
9393
|
+
} catch {
|
|
9394
|
+
copy.classList.add("failed");
|
|
9395
|
+
setTimeout(() => {
|
|
9396
|
+
copy.classList.remove("failed");
|
|
9397
|
+
}, 1200);
|
|
9398
|
+
}
|
|
9399
|
+
});
|
|
9400
|
+
return copy;
|
|
9401
|
+
}
|
|
9402
|
+
function createSourceTabs(active, textValue) {
|
|
8846
9403
|
const tabs = document.createElement("div");
|
|
8847
9404
|
tabs.className = "gdp-source-tabs";
|
|
8848
9405
|
const codeButton = document.createElement("button");
|
|
8849
9406
|
codeButton.type = "button";
|
|
9407
|
+
codeButton.dataset.sourceTab = "code";
|
|
8850
9408
|
codeButton.textContent = "Code";
|
|
8851
9409
|
codeButton.classList.toggle("active", active === "code");
|
|
8852
9410
|
tabs.appendChild(codeButton);
|
|
@@ -8854,10 +9412,13 @@
|
|
|
8854
9412
|
if (active === "preview") {
|
|
8855
9413
|
previewButton = document.createElement("button");
|
|
8856
9414
|
previewButton.type = "button";
|
|
9415
|
+
previewButton.dataset.sourceTab = "preview";
|
|
8857
9416
|
previewButton.className = "active";
|
|
8858
9417
|
previewButton.textContent = "Preview";
|
|
8859
9418
|
tabs.prepend(previewButton);
|
|
8860
9419
|
}
|
|
9420
|
+
if (textValue != null)
|
|
9421
|
+
tabs.appendChild(createSourceCopyButton(textValue));
|
|
8861
9422
|
return { tabs, codeButton, previewButton };
|
|
8862
9423
|
}
|
|
8863
9424
|
async function renderSourceText(card, target, textValue, signal) {
|
|
@@ -8865,6 +9426,8 @@
|
|
|
8865
9426
|
`).replace(/\r/g, `
|
|
8866
9427
|
`).split(`
|
|
8867
9428
|
`) : [""];
|
|
9429
|
+
SOURCE_CURSOR_TOTALS.set(sourceCursorKey(target), lines.length);
|
|
9430
|
+
resetSourceCursorForTarget(target, lines.length);
|
|
8868
9431
|
const body = card.querySelector(".gdp-file-detail-body, .d2h-files-diff, .d2h-file-diff, .gdp-media, .gdp-source-viewer");
|
|
8869
9432
|
const isStandalone = card.classList.contains("gdp-standalone-source");
|
|
8870
9433
|
const view = document.createElement("div");
|
|
@@ -8885,7 +9448,7 @@
|
|
|
8885
9448
|
if (usesVirtualSource) {
|
|
8886
9449
|
const virtualCode = renderVirtualSource(target, textValue, lines, hljsRef, lang);
|
|
8887
9450
|
if (previewable) {
|
|
8888
|
-
const { tabs: tabs2, codeButton: codeButton2, previewButton: previewButton2 } = createSourceTabs("preview");
|
|
9451
|
+
const { tabs: tabs2, codeButton: codeButton2, previewButton: previewButton2 } = createSourceTabs("preview", textValue);
|
|
8889
9452
|
if (tabsHost) {
|
|
8890
9453
|
tabsHost.hidden = false;
|
|
8891
9454
|
tabsHost.replaceChildren(tabs2);
|
|
@@ -8947,6 +9510,7 @@
|
|
|
8947
9510
|
const tr = document.createElement("tr");
|
|
8948
9511
|
tr.dataset.line = String(index + 1);
|
|
8949
9512
|
tr.classList.toggle("gdp-source-line-target", lineInSourceTarget(index + 1, currentSourceLineTarget(target)));
|
|
9513
|
+
tr.classList.toggle("gdp-source-cursor", sourceCursorMatches(target, index + 1));
|
|
8950
9514
|
const num = document.createElement("td");
|
|
8951
9515
|
num.className = "gdp-source-line-number";
|
|
8952
9516
|
num.textContent = String(index + 1);
|
|
@@ -8969,7 +9533,7 @@
|
|
|
8969
9533
|
}
|
|
8970
9534
|
}
|
|
8971
9535
|
table2.appendChild(tbody);
|
|
8972
|
-
const { tabs, codeButton, previewButton } = createSourceTabs(previewable ? "preview" : "code");
|
|
9536
|
+
const { tabs, codeButton, previewButton } = createSourceTabs(previewable ? "preview" : "code", textValue);
|
|
8973
9537
|
if (tabsHost) {
|
|
8974
9538
|
tabsHost.hidden = false;
|
|
8975
9539
|
tabsHost.replaceChildren(tabs);
|
|
@@ -9120,19 +9684,21 @@
|
|
|
9120
9684
|
actions.className = "gdp-source-virtual-actions";
|
|
9121
9685
|
const copy = document.createElement("button");
|
|
9122
9686
|
copy.type = "button";
|
|
9123
|
-
copy.className = "gdp-source-virtual-
|
|
9124
|
-
copy.
|
|
9687
|
+
copy.className = "gdp-file-header-icon gdp-copy-source gdp-source-virtual-copy";
|
|
9688
|
+
copy.title = "Copy source";
|
|
9689
|
+
copy.setAttribute("aria-label", "Copy source");
|
|
9690
|
+
copy.innerHTML = iconSvg("octicon-copy", COPY_16_PATHS);
|
|
9125
9691
|
copy.addEventListener("click", async () => {
|
|
9126
9692
|
try {
|
|
9127
9693
|
await navigator.clipboard.writeText(textValue);
|
|
9128
|
-
copy.
|
|
9694
|
+
copy.classList.add("copied");
|
|
9129
9695
|
setTimeout(() => {
|
|
9130
|
-
copy.
|
|
9696
|
+
copy.classList.remove("copied");
|
|
9131
9697
|
}, 1200);
|
|
9132
9698
|
} catch {
|
|
9133
|
-
copy.
|
|
9699
|
+
copy.classList.add("failed");
|
|
9134
9700
|
setTimeout(() => {
|
|
9135
|
-
copy.
|
|
9701
|
+
copy.classList.remove("failed");
|
|
9136
9702
|
}, 1600);
|
|
9137
9703
|
}
|
|
9138
9704
|
});
|
|
@@ -9180,6 +9746,7 @@
|
|
|
9180
9746
|
row.className = "gdp-source-virtual-row";
|
|
9181
9747
|
row.dataset.line = String(index + 1);
|
|
9182
9748
|
row.classList.toggle("gdp-source-line-target", lineInSourceTarget(index + 1, currentSourceLineTarget(target)));
|
|
9749
|
+
row.classList.toggle("gdp-source-cursor", sourceCursorMatches(target, index + 1));
|
|
9183
9750
|
const num = document.createElement("span");
|
|
9184
9751
|
num.className = "gdp-source-virtual-line-number";
|
|
9185
9752
|
num.textContent = String(index + 1);
|
|
@@ -9206,6 +9773,7 @@
|
|
|
9206
9773
|
if (!raf)
|
|
9207
9774
|
raf = requestAnimationFrame(render);
|
|
9208
9775
|
};
|
|
9776
|
+
scroller.__gdpRenderVirtualSource = render;
|
|
9209
9777
|
scroller.addEventListener("scroll", schedule, { passive: true });
|
|
9210
9778
|
let resizeObserver = null;
|
|
9211
9779
|
resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(() => {
|
|
@@ -9241,6 +9809,12 @@
|
|
|
9241
9809
|
video.controls = true;
|
|
9242
9810
|
video.preload = "metadata";
|
|
9243
9811
|
view.appendChild(video);
|
|
9812
|
+
} else if (mediaKind === "audio") {
|
|
9813
|
+
const audio = document.createElement("audio");
|
|
9814
|
+
audio.src = url;
|
|
9815
|
+
audio.controls = true;
|
|
9816
|
+
audio.preload = "metadata";
|
|
9817
|
+
view.appendChild(audio);
|
|
9244
9818
|
} else if (mediaKind === "pdf") {
|
|
9245
9819
|
const frame = document.createElement("iframe");
|
|
9246
9820
|
frame.src = url;
|
|
@@ -9407,7 +9981,7 @@
|
|
|
9407
9981
|
renderSourceUnsupported(card, target);
|
|
9408
9982
|
return;
|
|
9409
9983
|
}
|
|
9410
|
-
if (displayKind === "image" || displayKind === "video" || displayKind === "pdf") {
|
|
9984
|
+
if (displayKind === "image" || displayKind === "video" || displayKind === "audio" || displayKind === "pdf") {
|
|
9411
9985
|
if (req !== SOURCE_REQ_SEQ || !sourceTargetsEqual(sourceTargetFromRoute(), target))
|
|
9412
9986
|
return;
|
|
9413
9987
|
finishSourceLoad(req);
|
|
@@ -9803,9 +10377,10 @@
|
|
|
9803
10377
|
b2.addEventListener("scroll", () => mirror(b2, a2), { passive: true });
|
|
9804
10378
|
});
|
|
9805
10379
|
}
|
|
9806
|
-
const MEDIA_RE = /\.(png|jpe?g|gif|webp|svg|avif|bmp|ico|mp4|webm|mov)(\?.*)?$/i;
|
|
10380
|
+
const MEDIA_RE = /\.(png|jpe?g|gif|webp|svg|avif|bmp|ico|mp4|webm|mov|mp3|wav|ogg|flac|m4a|aac|opus)(\?.*)?$/i;
|
|
9807
10381
|
const IMAGE_RE = /\.(png|jpe?g|gif|webp|svg|avif|bmp|ico)(\?.*)?$/i;
|
|
9808
10382
|
const VIDEO_RE = /\.(mp4|webm|mov)$/i;
|
|
10383
|
+
const AUDIO_RE = /\.(mp3|wav|ogg|flac|m4a|aac|opus)$/i;
|
|
9809
10384
|
function isMedia(p2) {
|
|
9810
10385
|
return MEDIA_RE.test(p2);
|
|
9811
10386
|
}
|
|
@@ -9815,6 +10390,9 @@
|
|
|
9815
10390
|
function isVideo(p2) {
|
|
9816
10391
|
return VIDEO_RE.test(p2);
|
|
9817
10392
|
}
|
|
10393
|
+
function isAudio(p2) {
|
|
10394
|
+
return AUDIO_RE.test(p2);
|
|
10395
|
+
}
|
|
9818
10396
|
function fileURL(path, ref) {
|
|
9819
10397
|
return "/_file?path=" + encodeURIComponent(path) + "&ref=" + ref;
|
|
9820
10398
|
}
|
|
@@ -9823,6 +10401,9 @@
|
|
|
9823
10401
|
if (isVideo(path)) {
|
|
9824
10402
|
return '<video src="' + url + '" controls preload="metadata"></video>';
|
|
9825
10403
|
}
|
|
10404
|
+
if (isAudio(path)) {
|
|
10405
|
+
return '<audio src="' + url + '" controls preload="metadata"></audio>';
|
|
10406
|
+
}
|
|
9826
10407
|
return '<img src="' + url + '" alt="" loading="lazy">';
|
|
9827
10408
|
}
|
|
9828
10409
|
function enhanceMediaCard(file, card) {
|
|
@@ -9916,12 +10497,21 @@
|
|
|
9916
10497
|
b2.addEventListener("click", () => {
|
|
9917
10498
|
STATE.sbView = b2.dataset.view || "tree";
|
|
9918
10499
|
localStorage.setItem("gdp:sbview", STATE.sbView);
|
|
9919
|
-
if (
|
|
9920
|
-
renderSidebar(
|
|
10500
|
+
if (SIDEBAR_FILES.length)
|
|
10501
|
+
renderSidebar(SIDEBAR_FILES, SIDEBAR_ON_FILE_CLICK);
|
|
9921
10502
|
});
|
|
9922
10503
|
});
|
|
9923
10504
|
$("#sb-expand-all").addEventListener("click", () => setAllSidebarDirsCollapsed(false));
|
|
9924
10505
|
$("#sb-collapse-all").addEventListener("click", () => setAllSidebarDirsCollapsed(true));
|
|
10506
|
+
prepareKeyboardPanels();
|
|
10507
|
+
const contentPanel = document.querySelector("#content");
|
|
10508
|
+
contentPanel?.addEventListener("focusin", () => setPanelFocusScope("main"));
|
|
10509
|
+
contentPanel?.addEventListener("mousedown", (event) => {
|
|
10510
|
+
if (isFocusableClickTarget(event.target))
|
|
10511
|
+
setPanelFocusScope("main");
|
|
10512
|
+
else
|
|
10513
|
+
focusMainPanel();
|
|
10514
|
+
});
|
|
9925
10515
|
function applySidebarWidth(w) {
|
|
9926
10516
|
const cw = Math.max(180, Math.min(900, w));
|
|
9927
10517
|
document.documentElement.style.setProperty("--sidebar-w", cw + "px");
|
|
@@ -9940,6 +10530,13 @@
|
|
|
9940
10530
|
sb.addEventListener("mousedown", mark);
|
|
9941
10531
|
sb.addEventListener("touchstart", mark, { passive: true });
|
|
9942
10532
|
sb.addEventListener("scroll", mark, { passive: true });
|
|
10533
|
+
sb.addEventListener("focusin", () => setPanelFocusScope("sidebar"));
|
|
10534
|
+
sb.addEventListener("mousedown", (event) => {
|
|
10535
|
+
if (isFocusableClickTarget(event.target))
|
|
10536
|
+
setPanelFocusScope("sidebar");
|
|
10537
|
+
else
|
|
10538
|
+
focusSidebarPanel();
|
|
10539
|
+
});
|
|
9943
10540
|
})();
|
|
9944
10541
|
(function setupResizer() {
|
|
9945
10542
|
const handle = $("#sidebar-resizer");
|
|
@@ -10002,6 +10599,32 @@
|
|
|
10002
10599
|
function visibleSidebarItems() {
|
|
10003
10600
|
return $$("#filelist li[data-path], #filelist .tree-dir[data-dirpath]").filter(isSidebarRowVisible);
|
|
10004
10601
|
}
|
|
10602
|
+
function scrollSidebarItemIntoView(item, block2 = "nearest") {
|
|
10603
|
+
const sidebar = document.querySelector("#sidebar");
|
|
10604
|
+
if (!sidebar) {
|
|
10605
|
+
item.scrollIntoView({ block: block2 });
|
|
10606
|
+
return;
|
|
10607
|
+
}
|
|
10608
|
+
const sidebarRect = sidebar.getBoundingClientRect();
|
|
10609
|
+
const itemRect = item.getBoundingClientRect();
|
|
10610
|
+
const stickyBottom = Math.max(sidebarRect.top, document.querySelector(".sb-head")?.getBoundingClientRect().bottom || sidebarRect.top, document.querySelector(".sb-filter-wrap")?.getBoundingClientRect().bottom || sidebarRect.top);
|
|
10611
|
+
const topPadding = Math.max(8, stickyBottom - sidebarRect.top + 8);
|
|
10612
|
+
const bottomPadding = 14;
|
|
10613
|
+
const visibleTop = sidebarRect.top + topPadding;
|
|
10614
|
+
const visibleBottom = sidebarRect.bottom - bottomPadding;
|
|
10615
|
+
if (block2 === "start") {
|
|
10616
|
+
sidebar.scrollTop += itemRect.top - visibleTop;
|
|
10617
|
+
return;
|
|
10618
|
+
}
|
|
10619
|
+
if (block2 === "end") {
|
|
10620
|
+
sidebar.scrollTop += itemRect.bottom - visibleBottom;
|
|
10621
|
+
return;
|
|
10622
|
+
}
|
|
10623
|
+
if (itemRect.top < visibleTop)
|
|
10624
|
+
sidebar.scrollTop += itemRect.top - visibleTop;
|
|
10625
|
+
else if (itemRect.bottom > visibleBottom)
|
|
10626
|
+
sidebar.scrollTop += itemRect.bottom - visibleBottom;
|
|
10627
|
+
}
|
|
10005
10628
|
function isRepositorySidebarMode() {
|
|
10006
10629
|
return document.body.classList.contains("gdp-repo-page") || document.body.classList.contains("gdp-repo-blob-page");
|
|
10007
10630
|
}
|
|
@@ -10017,7 +10640,44 @@
|
|
|
10017
10640
|
const path = target.dataset.path || target.dataset.dirpath;
|
|
10018
10641
|
if (path)
|
|
10019
10642
|
markActive(path);
|
|
10020
|
-
target
|
|
10643
|
+
scrollSidebarItemIntoView(target);
|
|
10644
|
+
if (target.dataset.path)
|
|
10645
|
+
prefetchByPath(target.dataset.path);
|
|
10646
|
+
}
|
|
10647
|
+
function moveActiveSidebarPage(direction) {
|
|
10648
|
+
const items = visibleSidebarItems();
|
|
10649
|
+
if (!items.length)
|
|
10650
|
+
return;
|
|
10651
|
+
const repoSidebar = isRepositorySidebarMode();
|
|
10652
|
+
const sidebar = document.querySelector("#sidebar");
|
|
10653
|
+
const sample = items.find((item) => item.getBoundingClientRect().height > 0);
|
|
10654
|
+
const rowHeight = sample ? sample.getBoundingClientRect().height : 28;
|
|
10655
|
+
const halfPageRows = Math.max(1, Math.floor((sidebar?.clientHeight || window.innerHeight) / 2 / rowHeight));
|
|
10656
|
+
const current = items.findIndex((li) => li.classList.contains("active"));
|
|
10657
|
+
const start = current < 0 ? 0 : current;
|
|
10658
|
+
const idx = Math.max(0, Math.min(items.length - 1, start + direction * halfPageRows));
|
|
10659
|
+
const target = items[idx];
|
|
10660
|
+
const path = target.dataset.path || target.dataset.dirpath;
|
|
10661
|
+
if (!repoSidebar && target.dataset.path)
|
|
10662
|
+
target.click();
|
|
10663
|
+
else if (path)
|
|
10664
|
+
markActive(path);
|
|
10665
|
+
scrollSidebarItemIntoView(target);
|
|
10666
|
+
if (target.dataset.path)
|
|
10667
|
+
prefetchByPath(target.dataset.path);
|
|
10668
|
+
}
|
|
10669
|
+
function moveActiveSidebarToEdge(edge) {
|
|
10670
|
+
const items = visibleSidebarItems();
|
|
10671
|
+
const repoSidebar = isRepositorySidebarMode();
|
|
10672
|
+
const target = edge === "top" ? items[0] : items[items.length - 1];
|
|
10673
|
+
if (!target)
|
|
10674
|
+
return;
|
|
10675
|
+
const path = target.dataset.path || target.dataset.dirpath;
|
|
10676
|
+
if (!repoSidebar && target.dataset.path)
|
|
10677
|
+
target.click();
|
|
10678
|
+
else if (path)
|
|
10679
|
+
markActive(path);
|
|
10680
|
+
scrollSidebarItemIntoView(target, edge === "top" ? "start" : "end");
|
|
10021
10681
|
if (target.dataset.path)
|
|
10022
10682
|
prefetchByPath(target.dataset.path);
|
|
10023
10683
|
}
|
|
@@ -10099,13 +10759,16 @@
|
|
|
10099
10759
|
function closeSearchPalette() {
|
|
10100
10760
|
if (!PALETTE)
|
|
10101
10761
|
return;
|
|
10762
|
+
const previousFocusScope = PALETTE.previousFocusScope;
|
|
10102
10763
|
PALETTE.controller?.abort();
|
|
10103
10764
|
if (PALETTE.debounce)
|
|
10104
10765
|
window.clearTimeout(PALETTE.debounce);
|
|
10105
10766
|
PALETTE.root.remove();
|
|
10106
10767
|
PALETTE = null;
|
|
10768
|
+
restorePanelFocusScope(previousFocusScope);
|
|
10107
10769
|
}
|
|
10108
10770
|
function createPalette(mode) {
|
|
10771
|
+
const previousFocusScope = PALETTE ? PALETTE.previousFocusScope : getPanelFocusScope();
|
|
10109
10772
|
closeSearchPalette();
|
|
10110
10773
|
const root = document.createElement("div");
|
|
10111
10774
|
root.className = "gdp-palette-backdrop";
|
|
@@ -10147,9 +10810,11 @@
|
|
|
10147
10810
|
selected: -1,
|
|
10148
10811
|
items: [],
|
|
10149
10812
|
composing: false,
|
|
10150
|
-
diffSnapshot: [...STATE.files]
|
|
10813
|
+
diffSnapshot: [...STATE.files],
|
|
10814
|
+
previousFocusScope
|
|
10151
10815
|
};
|
|
10152
10816
|
PALETTE = state;
|
|
10817
|
+
setPanelFocusScope(null);
|
|
10153
10818
|
root.addEventListener("mousedown", (e2) => {
|
|
10154
10819
|
if (e2.target === root)
|
|
10155
10820
|
closeSearchPalette();
|
|
@@ -10468,78 +11133,140 @@
|
|
|
10468
11133
|
function openSearchPalette(mode) {
|
|
10469
11134
|
createPalette(mode);
|
|
10470
11135
|
}
|
|
10471
|
-
|
|
10472
|
-
if (
|
|
10473
|
-
|
|
10474
|
-
|
|
10475
|
-
return;
|
|
10476
|
-
openSearchPalette("file");
|
|
10477
|
-
return;
|
|
11136
|
+
function dispatchKeymapAction(action, scope, repeated = false) {
|
|
11137
|
+
if (action !== "start-g-sequence") {
|
|
11138
|
+
PENDING_G_SCOPE = null;
|
|
11139
|
+
PENDING_G_UNTIL = 0;
|
|
10478
11140
|
}
|
|
10479
|
-
if (
|
|
10480
|
-
|
|
10481
|
-
|
|
10482
|
-
|
|
10483
|
-
openSearchPalette("grep");
|
|
10484
|
-
return;
|
|
11141
|
+
if (action === "open-file-palette") {
|
|
11142
|
+
if (PALETTE?.mode !== "file")
|
|
11143
|
+
openSearchPalette("file");
|
|
11144
|
+
return true;
|
|
10485
11145
|
}
|
|
10486
|
-
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
if (cancelActiveSourceLoad("esc")) {
|
|
10491
|
-
e2.preventDefault();
|
|
10492
|
-
return;
|
|
10493
|
-
}
|
|
11146
|
+
if (action === "open-grep-palette") {
|
|
11147
|
+
if (PALETTE?.mode !== "grep")
|
|
11148
|
+
openSearchPalette("grep");
|
|
11149
|
+
return true;
|
|
10494
11150
|
}
|
|
10495
|
-
if (
|
|
10496
|
-
e2.preventDefault();
|
|
11151
|
+
if (action === "focus-file-filter") {
|
|
10497
11152
|
focusFileFilter();
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
}
|
|
10504
|
-
|
|
11153
|
+
return true;
|
|
11154
|
+
}
|
|
11155
|
+
if (action === "focus-sidebar") {
|
|
11156
|
+
focusSidebarPanel();
|
|
11157
|
+
return true;
|
|
11158
|
+
}
|
|
11159
|
+
if (action === "focus-main") {
|
|
11160
|
+
focusMainPanel();
|
|
11161
|
+
return true;
|
|
11162
|
+
}
|
|
11163
|
+
if (action === "cancel-source-load") {
|
|
11164
|
+
cancelActiveSourceLoad("esc");
|
|
11165
|
+
return true;
|
|
11166
|
+
}
|
|
11167
|
+
if (action === "open-sidebar-item") {
|
|
11168
|
+
if (!isRepositorySidebarMode())
|
|
11169
|
+
return false;
|
|
11170
|
+
openActiveSidebarItem();
|
|
11171
|
+
focusMainPanel();
|
|
11172
|
+
return true;
|
|
11173
|
+
}
|
|
11174
|
+
if (action === "sidebar-next" || action === "sidebar-previous") {
|
|
10505
11175
|
const repoSidebar = isRepositorySidebarMode();
|
|
10506
11176
|
const items = repoSidebar ? visibleSidebarItems() : $$("#filelist li[data-path]:not(.hidden):not(.hidden-by-tests)");
|
|
10507
11177
|
if (!items.length)
|
|
10508
|
-
return;
|
|
11178
|
+
return true;
|
|
10509
11179
|
let idx = items.findIndex((li) => li.classList.contains("active"));
|
|
10510
11180
|
if (idx < 0)
|
|
10511
11181
|
idx = 0;
|
|
10512
11182
|
else
|
|
10513
|
-
idx =
|
|
11183
|
+
idx = action === "sidebar-next" ? Math.min(items.length - 1, idx + 1) : Math.max(0, idx - 1);
|
|
10514
11184
|
const target = items[idx];
|
|
10515
11185
|
const path = target?.dataset.path || target?.dataset.dirpath;
|
|
10516
11186
|
if (!repoSidebar && target) {
|
|
10517
11187
|
target.click();
|
|
10518
|
-
target
|
|
11188
|
+
scrollSidebarItemIntoView(target);
|
|
10519
11189
|
} else if (path) {
|
|
10520
11190
|
markActive(path);
|
|
10521
|
-
target
|
|
11191
|
+
scrollSidebarItemIntoView(target);
|
|
10522
11192
|
}
|
|
10523
|
-
const nextIdx =
|
|
11193
|
+
const nextIdx = action === "sidebar-next" ? Math.min(items.length - 1, idx + 1) : Math.max(0, idx - 1);
|
|
10524
11194
|
const nextItem = items[nextIdx];
|
|
10525
11195
|
if (nextItem && nextItem !== target && nextItem.dataset.path)
|
|
10526
11196
|
prefetchByPath(nextItem.dataset.path);
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
}
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
11197
|
+
return true;
|
|
11198
|
+
}
|
|
11199
|
+
if (action === "sidebar-page-down" || action === "sidebar-page-up") {
|
|
11200
|
+
moveActiveSidebarPage(action === "sidebar-page-down" ? 1 : -1);
|
|
11201
|
+
return true;
|
|
11202
|
+
}
|
|
11203
|
+
if (action === "sidebar-expand") {
|
|
11204
|
+
if (!isRepositorySidebarMode())
|
|
11205
|
+
return false;
|
|
11206
|
+
toggleActiveSidebarDirectoryCollapsed();
|
|
11207
|
+
return true;
|
|
11208
|
+
}
|
|
11209
|
+
if (action === "sidebar-collapse") {
|
|
11210
|
+
if (!isRepositorySidebarMode())
|
|
11211
|
+
return false;
|
|
11212
|
+
setActiveSidebarDirectoryCollapsed(true);
|
|
11213
|
+
return true;
|
|
11214
|
+
}
|
|
11215
|
+
if (action === "scroll-main-down" || action === "scroll-main-up") {
|
|
11216
|
+
scrollMainPanel(action === "scroll-main-down" ? 1 : -1, repeated);
|
|
11217
|
+
return true;
|
|
11218
|
+
}
|
|
11219
|
+
if (action === "scroll-main-page-down" || action === "scroll-main-page-up") {
|
|
11220
|
+
scrollMainPanel(action === "scroll-main-page-down" ? 1 : -1, repeated, "page");
|
|
11221
|
+
return true;
|
|
11222
|
+
}
|
|
11223
|
+
if (action === "tab-preview" || action === "tab-code") {
|
|
11224
|
+
return switchSourceTab(action === "tab-preview" ? "preview" : "code");
|
|
11225
|
+
}
|
|
11226
|
+
if (action === "start-g-sequence") {
|
|
11227
|
+
PENDING_G_SCOPE = scope;
|
|
11228
|
+
PENDING_G_UNTIL = performance.now() + 900;
|
|
11229
|
+
return true;
|
|
11230
|
+
}
|
|
11231
|
+
if (action === "goto-top" || action === "goto-bottom") {
|
|
11232
|
+
const edge = action === "goto-top" ? "top" : "bottom";
|
|
11233
|
+
if (scope === "main")
|
|
11234
|
+
scrollMainToEdge(edge);
|
|
11235
|
+
else if (scope === "sidebar")
|
|
11236
|
+
moveActiveSidebarToEdge(edge);
|
|
11237
|
+
else
|
|
11238
|
+
window.scrollTo({ top: edge === "top" ? 0 : Math.max(document.documentElement.scrollHeight, document.body.scrollHeight), behavior: "auto" });
|
|
11239
|
+
return true;
|
|
11240
|
+
}
|
|
11241
|
+
if (action === "layout-unified") {
|
|
10538
11242
|
setLayout("line-by-line");
|
|
10539
|
-
|
|
11243
|
+
return true;
|
|
11244
|
+
}
|
|
11245
|
+
if (action === "layout-split") {
|
|
10540
11246
|
setLayout("side-by-side");
|
|
10541
|
-
|
|
11247
|
+
return true;
|
|
11248
|
+
}
|
|
11249
|
+
if (action === "toggle-theme") {
|
|
10542
11250
|
$("#theme").click();
|
|
11251
|
+
return true;
|
|
11252
|
+
}
|
|
11253
|
+
return false;
|
|
11254
|
+
}
|
|
11255
|
+
document.addEventListener("keydown", (e2) => {
|
|
11256
|
+
const targetEl = e2.target;
|
|
11257
|
+
const scope = keymapScope(targetEl);
|
|
11258
|
+
const action = resolveKeymapAction(e2, {
|
|
11259
|
+
scope,
|
|
11260
|
+
editable: isEditableKeyTarget(targetEl),
|
|
11261
|
+
composing: e2.isComposing,
|
|
11262
|
+
paletteOpen: !!PALETTE,
|
|
11263
|
+
pendingG: PENDING_G_SCOPE === scope && performance.now() <= PENDING_G_UNTIL,
|
|
11264
|
+
lightboxOpen: !!document.querySelector(".mkdp-lightbox")
|
|
11265
|
+
});
|
|
11266
|
+
if (!action)
|
|
11267
|
+
return;
|
|
11268
|
+
if (dispatchKeymapAction(action, scope, e2.repeat))
|
|
11269
|
+
e2.preventDefault();
|
|
10543
11270
|
});
|
|
10544
11271
|
applyTheme();
|
|
10545
11272
|
setLayout(STATE.layout);
|
|
@@ -10566,6 +11293,12 @@
|
|
|
10566
11293
|
}).catch(() => setStatus("error"));
|
|
10567
11294
|
}
|
|
10568
11295
|
function load(options = {}) {
|
|
11296
|
+
if (STATE.route.screen === "help") {
|
|
11297
|
+
setStatus("live");
|
|
11298
|
+
renderHelpPage();
|
|
11299
|
+
syncHeaderMenu();
|
|
11300
|
+
return Promise.resolve();
|
|
11301
|
+
}
|
|
10569
11302
|
if (STATE.route.screen === "repo")
|
|
10570
11303
|
return loadRepo();
|
|
10571
11304
|
setStatus("refreshing");
|
|
@@ -10584,7 +11317,10 @@
|
|
|
10584
11317
|
setStatus("live");
|
|
10585
11318
|
}).catch(() => setStatus("error"));
|
|
10586
11319
|
}
|
|
10587
|
-
if (STATE.route.screen === "
|
|
11320
|
+
if (STATE.route.screen === "help") {
|
|
11321
|
+
setStatus("live");
|
|
11322
|
+
renderHelpPage();
|
|
11323
|
+
} else if (STATE.route.screen === "repo")
|
|
10588
11324
|
loadRepo();
|
|
10589
11325
|
else if (STATE.route.screen === "file" && STATE.route.view === "blob") {
|
|
10590
11326
|
setStatus("live");
|
|
@@ -10607,10 +11343,13 @@
|
|
|
10607
11343
|
const range = currentRange();
|
|
10608
11344
|
if (STATE.route.screen === "file") {
|
|
10609
11345
|
setRoute({ screen: "file", path: STATE.route.path, ref: STATE.route.ref, range }, true);
|
|
11346
|
+
} else if (STATE.route.screen === "help") {
|
|
11347
|
+
setRoute({ screen: "help", lang: helpLanguageFromRoute(), section: helpSectionFromRoute(), range }, true);
|
|
11348
|
+
renderHelpPage();
|
|
10610
11349
|
} else {
|
|
10611
11350
|
setRoute({ screen: "diff", range }, true);
|
|
11351
|
+
load();
|
|
10612
11352
|
}
|
|
10613
|
-
load();
|
|
10614
11353
|
}
|
|
10615
11354
|
syncRefInputs();
|
|
10616
11355
|
syncHeaderMenu();
|
|
@@ -10811,6 +11550,13 @@
|
|
|
10811
11550
|
STATE.repoRef = STATE.route.ref || "worktree";
|
|
10812
11551
|
syncRefInputs();
|
|
10813
11552
|
syncHeaderMenu();
|
|
11553
|
+
if (STATE.route.screen === "help") {
|
|
11554
|
+
cancelActiveSourceLoad("navigation");
|
|
11555
|
+
setPageMode();
|
|
11556
|
+
renderHelpPage();
|
|
11557
|
+
setStatus("live");
|
|
11558
|
+
return;
|
|
11559
|
+
}
|
|
10814
11560
|
if (STATE.route.screen === "repo") {
|
|
10815
11561
|
cancelActiveSourceLoad("navigation");
|
|
10816
11562
|
setPageMode();
|