@youtyan/code-viewer 0.1.24 → 0.1.26
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/README.md +3 -0
- package/dist/code-viewer.js +436 -47
- package/package.json +1 -1
- package/web/app.js +516 -75
- package/web/index.html +3 -1
- package/web/style.css +168 -3
package/web/app.js
CHANGED
|
@@ -6942,7 +6942,13 @@ ${frontmatter.yaml}
|
|
|
6942
6942
|
let SIDEBAR_ROW_BY_PATH = new Map;
|
|
6943
6943
|
let SIDEBAR_VIRTUAL_ACTIVE_PATH = "";
|
|
6944
6944
|
const SIDEBAR_TREE_ITEMS_CACHE = new WeakMap;
|
|
6945
|
+
let REPO_SORT = {
|
|
6946
|
+
key: "name",
|
|
6947
|
+
direction: "asc"
|
|
6948
|
+
};
|
|
6945
6949
|
let SERVER_SCOPE_OMIT_DIRS_DEFAULT = [];
|
|
6950
|
+
let SERVER_SCOPE_EXCLUDE_NAMES_DEFAULT = [];
|
|
6951
|
+
const UNDO_STACK = [];
|
|
6946
6952
|
let PENDING_G_SCOPE = null;
|
|
6947
6953
|
let PENDING_G_UNTIL = 0;
|
|
6948
6954
|
let SOURCE_CURSOR = null;
|
|
@@ -6950,6 +6956,7 @@ ${frontmatter.yaml}
|
|
|
6950
6956
|
const HELP_LANGUAGES = ["en", "ja"];
|
|
6951
6957
|
const HELP_SECTIONS = ["keybindings"];
|
|
6952
6958
|
const SCOPE_OMIT_DIRS_STORAGE_KEY_PREFIX = "gdp:scope-omit-dirs:";
|
|
6959
|
+
const SCOPE_EXCLUDE_NAMES_STORAGE_KEY_PREFIX = "gdp:scope-exclude-names:";
|
|
6953
6960
|
const SIDEBAR_FONT_SIZE_STORAGE_KEY = "gdp:sidebar-font-size";
|
|
6954
6961
|
const CODE_FONT_SIZE_STORAGE_KEY = "gdp:code-font-size";
|
|
6955
6962
|
const CLIENT_SCOPE_OMIT_DIRS_DEFAULT = [
|
|
@@ -6980,6 +6987,7 @@ ${frontmatter.yaml}
|
|
|
6980
6987
|
"bin",
|
|
6981
6988
|
"obj"
|
|
6982
6989
|
];
|
|
6990
|
+
const CLIENT_SCOPE_EXCLUDE_NAMES_DEFAULT = [".DS_Store"];
|
|
6983
6991
|
const HELP_CONTENT = {
|
|
6984
6992
|
en: {
|
|
6985
6993
|
languageLabel: "Language",
|
|
@@ -7251,9 +7259,18 @@ ${frontmatter.yaml}
|
|
|
7251
7259
|
...new Set(raw.map((item) => item.trim()).filter((item) => item && item.length <= 64 && !item.includes("/") && !item.includes("\\") && item !== "." && item !== ".." && item !== ".git"))
|
|
7252
7260
|
].slice(0, 100).sort((a2, b2) => a2.localeCompare(b2));
|
|
7253
7261
|
}
|
|
7262
|
+
function normalizeScopeExcludeNames(value) {
|
|
7263
|
+
const raw = Array.isArray(value) ? value : value.split(/[\n,]+/);
|
|
7264
|
+
return [
|
|
7265
|
+
...new Set(raw.map((item) => item.trim()).filter((item) => item && item.length <= 128 && !item.includes("/") && !item.includes("\\") && item !== "." && item !== ".." && item !== ".git"))
|
|
7266
|
+
].slice(0, 200).sort((a2, b2) => a2.localeCompare(b2));
|
|
7267
|
+
}
|
|
7254
7268
|
function scopeOmitDirsStorageKey() {
|
|
7255
7269
|
return SCOPE_OMIT_DIRS_STORAGE_KEY_PREFIX + (PROJECT_NAME || "default");
|
|
7256
7270
|
}
|
|
7271
|
+
function scopeExcludeNamesStorageKey() {
|
|
7272
|
+
return SCOPE_EXCLUDE_NAMES_STORAGE_KEY_PREFIX + (PROJECT_NAME || "default");
|
|
7273
|
+
}
|
|
7257
7274
|
function setProjectName(project) {
|
|
7258
7275
|
if (!project)
|
|
7259
7276
|
return;
|
|
@@ -7271,16 +7288,36 @@ ${frontmatter.yaml}
|
|
|
7271
7288
|
return normalizeScopeOmitDirs(raw);
|
|
7272
7289
|
}
|
|
7273
7290
|
}
|
|
7291
|
+
function savedScopeExcludeNames() {
|
|
7292
|
+
const raw = localStorage.getItem(scopeExcludeNamesStorageKey());
|
|
7293
|
+
if (raw == null)
|
|
7294
|
+
return null;
|
|
7295
|
+
try {
|
|
7296
|
+
const parsed = JSON.parse(raw);
|
|
7297
|
+
return normalizeScopeExcludeNames(Array.isArray(parsed) ? parsed : []);
|
|
7298
|
+
} catch {
|
|
7299
|
+
return normalizeScopeExcludeNames(raw);
|
|
7300
|
+
}
|
|
7301
|
+
}
|
|
7274
7302
|
function serverScopeOmitDirsDefault() {
|
|
7275
7303
|
return SERVER_SCOPE_OMIT_DIRS_DEFAULT.length ? SERVER_SCOPE_OMIT_DIRS_DEFAULT : CLIENT_SCOPE_OMIT_DIRS_DEFAULT;
|
|
7276
7304
|
}
|
|
7305
|
+
function serverScopeExcludeNamesDefault() {
|
|
7306
|
+
return SERVER_SCOPE_EXCLUDE_NAMES_DEFAULT.length ? SERVER_SCOPE_EXCLUDE_NAMES_DEFAULT : CLIENT_SCOPE_EXCLUDE_NAMES_DEFAULT;
|
|
7307
|
+
}
|
|
7277
7308
|
function effectiveScopeOmitDirs() {
|
|
7278
7309
|
return savedScopeOmitDirs() ?? serverScopeOmitDirsDefault();
|
|
7279
7310
|
}
|
|
7280
|
-
function
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7311
|
+
function effectiveScopeExcludeNames() {
|
|
7312
|
+
return savedScopeExcludeNames() ?? serverScopeExcludeNamesDefault();
|
|
7313
|
+
}
|
|
7314
|
+
function appendScopeParams(params) {
|
|
7315
|
+
const omit = savedScopeOmitDirs();
|
|
7316
|
+
if (omit != null)
|
|
7317
|
+
params.set("omit_dirs", omit.join(","));
|
|
7318
|
+
const exclude = savedScopeExcludeNames();
|
|
7319
|
+
if (exclude != null)
|
|
7320
|
+
params.set("exclude_names", exclude.join(","));
|
|
7284
7321
|
}
|
|
7285
7322
|
function normalizeViewerFontSize(value) {
|
|
7286
7323
|
return value === "compact" || value === "large" || value === "xlarge" ? value : "regular";
|
|
@@ -7315,8 +7352,9 @@ ${frontmatter.yaml}
|
|
|
7315
7352
|
syncSidebarHeaderHeight();
|
|
7316
7353
|
}
|
|
7317
7354
|
function repoFileCacheKey(ref) {
|
|
7318
|
-
const
|
|
7319
|
-
|
|
7355
|
+
const omit = savedScopeOmitDirs();
|
|
7356
|
+
const exclude = savedScopeExcludeNames();
|
|
7357
|
+
return `${ref}\x00${omit ? omit.join("\x00") : "server"}\x00${exclude ? exclude.join("\x00") : "server"}`;
|
|
7320
7358
|
}
|
|
7321
7359
|
async function loadSettings() {
|
|
7322
7360
|
try {
|
|
@@ -7326,6 +7364,7 @@ ${frontmatter.yaml}
|
|
|
7326
7364
|
const settings = await res.json();
|
|
7327
7365
|
setProjectName(settings.project || "");
|
|
7328
7366
|
SERVER_SCOPE_OMIT_DIRS_DEFAULT = normalizeScopeOmitDirs(settings.scope.omit_dirs_effective);
|
|
7367
|
+
SERVER_SCOPE_EXCLUDE_NAMES_DEFAULT = normalizeScopeExcludeNames(settings.scope.exclude_names_effective);
|
|
7329
7368
|
return settings;
|
|
7330
7369
|
} catch {
|
|
7331
7370
|
return null;
|
|
@@ -7667,7 +7706,7 @@ ${frontmatter.yaml}
|
|
|
7667
7706
|
applySidebarHidden(!STATE.sidebarHidden);
|
|
7668
7707
|
}
|
|
7669
7708
|
function scopeOmitSourceLabel() {
|
|
7670
|
-
return savedScopeOmitDirs() != null ? "Browser override" : "Server default";
|
|
7709
|
+
return savedScopeOmitDirs() != null || savedScopeExcludeNames() != null ? "Browser override" : "Server default";
|
|
7671
7710
|
}
|
|
7672
7711
|
function refreshRepositoryTreeAfterSettings() {
|
|
7673
7712
|
REPO_FILE_CACHE.clear();
|
|
@@ -7683,15 +7722,18 @@ ${frontmatter.yaml}
|
|
|
7683
7722
|
async function openScopeSettings() {
|
|
7684
7723
|
const pop = document.querySelector("#scope-settings-popover");
|
|
7685
7724
|
const input = document.querySelector("#scope-omit-dirs");
|
|
7725
|
+
const excludeInput = document.querySelector("#scope-exclude-names");
|
|
7686
7726
|
const sidebarFontSize = document.querySelector("#sidebar-font-size");
|
|
7687
7727
|
const codeFontSize = document.querySelector("#code-font-size");
|
|
7688
7728
|
const source = document.querySelector("#scope-omit-source");
|
|
7689
|
-
if (!pop || !input || !sidebarFontSize || !codeFontSize || !source)
|
|
7729
|
+
if (!pop || !input || !excludeInput || !sidebarFontSize || !codeFontSize || !source)
|
|
7690
7730
|
return;
|
|
7691
7731
|
await loadSettings();
|
|
7692
7732
|
sidebarFontSize.value = savedSidebarFontSize();
|
|
7693
7733
|
codeFontSize.value = savedCodeFontSize();
|
|
7694
7734
|
input.value = effectiveScopeOmitDirs().join(`
|
|
7735
|
+
`);
|
|
7736
|
+
excludeInput.value = effectiveScopeExcludeNames().join(`
|
|
7695
7737
|
`);
|
|
7696
7738
|
source.textContent = 'Saved for project "' + (PROJECT_NAME || "default") + '" in this browser. Source: ' + scopeOmitSourceLabel() + ". Used by tree, Ctrl+K, and Ctrl+G. Reset removes the browser override.";
|
|
7697
7739
|
pop.hidden = false;
|
|
@@ -7704,15 +7746,17 @@ ${frontmatter.yaml}
|
|
|
7704
7746
|
}
|
|
7705
7747
|
function saveScopeSettings() {
|
|
7706
7748
|
const input = document.querySelector("#scope-omit-dirs");
|
|
7749
|
+
const excludeInput = document.querySelector("#scope-exclude-names");
|
|
7707
7750
|
const sidebarFontSize = document.querySelector("#sidebar-font-size");
|
|
7708
7751
|
const codeFontSize = document.querySelector("#code-font-size");
|
|
7709
|
-
if (!input || !sidebarFontSize || !codeFontSize)
|
|
7752
|
+
if (!input || !excludeInput || !sidebarFontSize || !codeFontSize)
|
|
7710
7753
|
return;
|
|
7711
7754
|
localStorage.setItem(SIDEBAR_FONT_SIZE_STORAGE_KEY, normalizeViewerFontSize(sidebarFontSize.value));
|
|
7712
7755
|
localStorage.setItem(CODE_FONT_SIZE_STORAGE_KEY, normalizeViewerFontSize(codeFontSize.value));
|
|
7713
7756
|
applySidebarFontSize();
|
|
7714
7757
|
applyCodeFontSize();
|
|
7715
7758
|
localStorage.setItem(scopeOmitDirsStorageKey(), JSON.stringify(normalizeScopeOmitDirs(input.value)));
|
|
7759
|
+
localStorage.setItem(scopeExcludeNamesStorageKey(), JSON.stringify(normalizeScopeExcludeNames(excludeInput.value)));
|
|
7716
7760
|
closeScopeSettings();
|
|
7717
7761
|
refreshRepositoryTreeAfterSettings();
|
|
7718
7762
|
}
|
|
@@ -7722,6 +7766,7 @@ ${frontmatter.yaml}
|
|
|
7722
7766
|
applySidebarFontSize("regular");
|
|
7723
7767
|
applyCodeFontSize("regular");
|
|
7724
7768
|
localStorage.removeItem(scopeOmitDirsStorageKey());
|
|
7769
|
+
localStorage.removeItem(scopeExcludeNamesStorageKey());
|
|
7725
7770
|
closeScopeSettings();
|
|
7726
7771
|
refreshRepositoryTreeAfterSettings();
|
|
7727
7772
|
}
|
|
@@ -7805,6 +7850,8 @@ ${frontmatter.yaml}
|
|
|
7805
7850
|
li.className = "tree-dir";
|
|
7806
7851
|
li.tabIndex = -1;
|
|
7807
7852
|
li.dataset.dirpath = dir.path;
|
|
7853
|
+
if (dir.children_omitted_reason)
|
|
7854
|
+
li.dataset.childrenOmittedReason = dir.children_omitted_reason;
|
|
7808
7855
|
if (dir.explicit)
|
|
7809
7856
|
li.dataset.explicit = "true";
|
|
7810
7857
|
if (dir.children_omitted) {
|
|
@@ -7948,6 +7995,8 @@ ${frontmatter.yaml}
|
|
|
7948
7995
|
li.className = "tree-dir";
|
|
7949
7996
|
li.tabIndex = -1;
|
|
7950
7997
|
li.dataset.dirpath = dir.path;
|
|
7998
|
+
if (dir.children_omitted_reason)
|
|
7999
|
+
li.dataset.childrenOmittedReason = dir.children_omitted_reason;
|
|
7951
8000
|
if (dir.explicit)
|
|
7952
8001
|
li.dataset.explicit = "true";
|
|
7953
8002
|
if (dir.children_omitted) {
|
|
@@ -8940,6 +8989,224 @@ ${frontmatter.yaml}
|
|
|
8940
8989
|
button.disabled = false;
|
|
8941
8990
|
}
|
|
8942
8991
|
}
|
|
8992
|
+
function closeRepoContextMenu() {
|
|
8993
|
+
document.querySelector(".gdp-context-menu")?.remove();
|
|
8994
|
+
}
|
|
8995
|
+
function closeTrashDialog() {
|
|
8996
|
+
document.querySelector(".gdp-trash-dialog-backdrop")?.remove();
|
|
8997
|
+
}
|
|
8998
|
+
function createTrashDialog(title, body, actions) {
|
|
8999
|
+
closeTrashDialog();
|
|
9000
|
+
const backdrop = document.createElement("div");
|
|
9001
|
+
backdrop.className = "gdp-trash-dialog-backdrop";
|
|
9002
|
+
const dialog = document.createElement("div");
|
|
9003
|
+
dialog.className = "gdp-trash-dialog";
|
|
9004
|
+
const titleId = "gdp-trash-dialog-title";
|
|
9005
|
+
const bodyId = "gdp-trash-dialog-body";
|
|
9006
|
+
dialog.setAttribute("role", "dialog");
|
|
9007
|
+
dialog.setAttribute("aria-modal", "true");
|
|
9008
|
+
dialog.setAttribute("aria-labelledby", titleId);
|
|
9009
|
+
dialog.setAttribute("aria-describedby", bodyId);
|
|
9010
|
+
const heading2 = document.createElement("div");
|
|
9011
|
+
heading2.id = titleId;
|
|
9012
|
+
heading2.className = "gdp-trash-dialog-title";
|
|
9013
|
+
heading2.textContent = title;
|
|
9014
|
+
const message = document.createElement("div");
|
|
9015
|
+
message.id = bodyId;
|
|
9016
|
+
message.className = "gdp-trash-dialog-body";
|
|
9017
|
+
message.textContent = body;
|
|
9018
|
+
const actionRow = document.createElement("div");
|
|
9019
|
+
actionRow.className = "gdp-trash-dialog-actions";
|
|
9020
|
+
actionRow.append(...actions);
|
|
9021
|
+
dialog.append(heading2, message, actionRow);
|
|
9022
|
+
backdrop.appendChild(dialog);
|
|
9023
|
+
document.body.appendChild(backdrop);
|
|
9024
|
+
return backdrop;
|
|
9025
|
+
}
|
|
9026
|
+
function confirmMoveToTrash(path, focusReturnTarget) {
|
|
9027
|
+
return new Promise((resolve) => {
|
|
9028
|
+
const previousFocus = focusReturnTarget || document.activeElement;
|
|
9029
|
+
const cancel = document.createElement("button");
|
|
9030
|
+
cancel.type = "button";
|
|
9031
|
+
cancel.className = "gdp-btn gdp-btn-sm";
|
|
9032
|
+
cancel.textContent = "Cancel";
|
|
9033
|
+
const move = document.createElement("button");
|
|
9034
|
+
move.type = "button";
|
|
9035
|
+
move.className = "gdp-btn gdp-btn-sm gdp-trash-dialog-danger";
|
|
9036
|
+
move.textContent = "Move to Trash";
|
|
9037
|
+
const done = (ok) => {
|
|
9038
|
+
document.removeEventListener("keydown", onKeydown);
|
|
9039
|
+
closeTrashDialog();
|
|
9040
|
+
previousFocus?.focus?.();
|
|
9041
|
+
resolve(ok);
|
|
9042
|
+
};
|
|
9043
|
+
const onKeydown = (event) => {
|
|
9044
|
+
if (event.key === "Escape") {
|
|
9045
|
+
event.preventDefault();
|
|
9046
|
+
event.stopPropagation();
|
|
9047
|
+
done(false);
|
|
9048
|
+
return;
|
|
9049
|
+
}
|
|
9050
|
+
if (event.key !== "Tab")
|
|
9051
|
+
return;
|
|
9052
|
+
const focusables = [cancel, move];
|
|
9053
|
+
const index = focusables.indexOf(document.activeElement);
|
|
9054
|
+
if (index < 0) {
|
|
9055
|
+
event.preventDefault();
|
|
9056
|
+
focusables[0].focus();
|
|
9057
|
+
return;
|
|
9058
|
+
}
|
|
9059
|
+
if (event.shiftKey && index <= 0) {
|
|
9060
|
+
event.preventDefault();
|
|
9061
|
+
focusables[focusables.length - 1].focus();
|
|
9062
|
+
} else if (!event.shiftKey && index === focusables.length - 1) {
|
|
9063
|
+
event.preventDefault();
|
|
9064
|
+
focusables[0].focus();
|
|
9065
|
+
}
|
|
9066
|
+
};
|
|
9067
|
+
cancel.addEventListener("click", () => done(false));
|
|
9068
|
+
move.addEventListener("click", () => done(true));
|
|
9069
|
+
const backdrop = createTrashDialog("Move to Trash?", `Move "${path}" to Trash?`, [cancel, move]);
|
|
9070
|
+
backdrop.addEventListener("pointerdown", (event) => {
|
|
9071
|
+
if (event.target === backdrop)
|
|
9072
|
+
done(false);
|
|
9073
|
+
});
|
|
9074
|
+
document.addEventListener("keydown", onKeydown);
|
|
9075
|
+
cancel.focus();
|
|
9076
|
+
});
|
|
9077
|
+
}
|
|
9078
|
+
function showTrashError(message) {
|
|
9079
|
+
const ok = document.createElement("button");
|
|
9080
|
+
ok.type = "button";
|
|
9081
|
+
ok.className = "gdp-btn gdp-btn-sm";
|
|
9082
|
+
ok.textContent = "OK";
|
|
9083
|
+
ok.addEventListener("click", closeTrashDialog);
|
|
9084
|
+
createTrashDialog("Trash failed", message, [ok]);
|
|
9085
|
+
ok.focus();
|
|
9086
|
+
}
|
|
9087
|
+
async function moveRepoPathToTrash(path) {
|
|
9088
|
+
const res = await fetch("/_trash_path", {
|
|
9089
|
+
method: "POST",
|
|
9090
|
+
headers: {
|
|
9091
|
+
"Content-Type": "application/json",
|
|
9092
|
+
"X-Code-Viewer-Action": "1"
|
|
9093
|
+
},
|
|
9094
|
+
body: JSON.stringify({ path })
|
|
9095
|
+
});
|
|
9096
|
+
if (!res.ok) {
|
|
9097
|
+
showTrashError(`Failed to move "${path}" to Trash: ${await res.text()}`);
|
|
9098
|
+
return false;
|
|
9099
|
+
}
|
|
9100
|
+
const body = await res.json();
|
|
9101
|
+
if (body.undo)
|
|
9102
|
+
UNDO_STACK.unshift(body.undo);
|
|
9103
|
+
return true;
|
|
9104
|
+
}
|
|
9105
|
+
async function runUndoAction(action) {
|
|
9106
|
+
if (action.type !== "trash")
|
|
9107
|
+
return false;
|
|
9108
|
+
const res = await fetch("/_restore_trash", {
|
|
9109
|
+
method: "POST",
|
|
9110
|
+
headers: {
|
|
9111
|
+
"Content-Type": "application/json",
|
|
9112
|
+
"X-Code-Viewer-Action": "1"
|
|
9113
|
+
},
|
|
9114
|
+
body: JSON.stringify(action.payload)
|
|
9115
|
+
});
|
|
9116
|
+
if (!res.ok) {
|
|
9117
|
+
showTrashError(`Failed to undo "${action.label}": ${await res.text()}`);
|
|
9118
|
+
return false;
|
|
9119
|
+
}
|
|
9120
|
+
return true;
|
|
9121
|
+
}
|
|
9122
|
+
async function undoLastAction() {
|
|
9123
|
+
const action = UNDO_STACK.shift();
|
|
9124
|
+
if (!action)
|
|
9125
|
+
return false;
|
|
9126
|
+
if (!await runUndoAction(action)) {
|
|
9127
|
+
UNDO_STACK.unshift(action);
|
|
9128
|
+
return true;
|
|
9129
|
+
}
|
|
9130
|
+
invalidateRepoSidebar();
|
|
9131
|
+
await load();
|
|
9132
|
+
return true;
|
|
9133
|
+
}
|
|
9134
|
+
async function requestMoveToTrash(path, onMoved, options = {}) {
|
|
9135
|
+
if (!await confirmMoveToTrash(path, options.focusReturnTarget))
|
|
9136
|
+
return;
|
|
9137
|
+
if (await moveRepoPathToTrash(path))
|
|
9138
|
+
onMoved();
|
|
9139
|
+
}
|
|
9140
|
+
function canTrashWorktreeRef(ref) {
|
|
9141
|
+
return ref === "worktree" || ref === "";
|
|
9142
|
+
}
|
|
9143
|
+
function showRepoContextMenu(event, entry, ref, onDeleted) {
|
|
9144
|
+
if (document.querySelector(".gdp-trash-dialog-backdrop"))
|
|
9145
|
+
return false;
|
|
9146
|
+
if (!canTrashWorktreeRef(ref))
|
|
9147
|
+
return false;
|
|
9148
|
+
if (entry.children_omitted_reason === "internal")
|
|
9149
|
+
return false;
|
|
9150
|
+
event.preventDefault();
|
|
9151
|
+
closeRepoContextMenu();
|
|
9152
|
+
const menu = document.createElement("div");
|
|
9153
|
+
menu.className = "gdp-context-menu";
|
|
9154
|
+
const anchor = event.target;
|
|
9155
|
+
const focusReturnTarget = anchor?.closest("li, .gdp-repo-row");
|
|
9156
|
+
const anchorRect = anchor?.closest("li, .gdp-repo-row")?.getBoundingClientRect();
|
|
9157
|
+
const anchorX = event.clientX > 0 ? event.clientX : anchorRect?.left || window.innerWidth / 2;
|
|
9158
|
+
const anchorY = event.clientY > 0 ? event.clientY : anchorRect?.bottom || window.innerHeight / 2;
|
|
9159
|
+
menu.style.left = `${anchorX}px`;
|
|
9160
|
+
menu.style.top = `${anchorY}px`;
|
|
9161
|
+
const trash = document.createElement("button");
|
|
9162
|
+
trash.type = "button";
|
|
9163
|
+
trash.className = "danger";
|
|
9164
|
+
trash.textContent = "Move to Trash...";
|
|
9165
|
+
trash.addEventListener("click", async () => {
|
|
9166
|
+
closeRepoContextMenu();
|
|
9167
|
+
await requestMoveToTrash(entry.path, onDeleted, { focusReturnTarget });
|
|
9168
|
+
});
|
|
9169
|
+
menu.appendChild(trash);
|
|
9170
|
+
document.body.appendChild(menu);
|
|
9171
|
+
const rect = menu.getBoundingClientRect();
|
|
9172
|
+
const left = Math.min(anchorX, window.innerWidth - rect.width - 8);
|
|
9173
|
+
const top = Math.min(anchorY, window.innerHeight - rect.height - 8);
|
|
9174
|
+
menu.style.left = `${Math.max(8, left)}px`;
|
|
9175
|
+
menu.style.top = `${Math.max(8, top)}px`;
|
|
9176
|
+
return true;
|
|
9177
|
+
}
|
|
9178
|
+
function sidebarTrashEntryFromEvent(event) {
|
|
9179
|
+
if (!isRepositorySidebarMode())
|
|
9180
|
+
return null;
|
|
9181
|
+
const row = event.target?.closest("#filelist li");
|
|
9182
|
+
if (!row)
|
|
9183
|
+
return null;
|
|
9184
|
+
const path = row.dataset.path || row.dataset.dirpath || "";
|
|
9185
|
+
if (!path)
|
|
9186
|
+
return null;
|
|
9187
|
+
return {
|
|
9188
|
+
path,
|
|
9189
|
+
children_omitted_reason: row.dataset.childrenOmittedReason
|
|
9190
|
+
};
|
|
9191
|
+
}
|
|
9192
|
+
function handleSidebarContextMenu(event) {
|
|
9193
|
+
const entry = sidebarTrashEntryFromEvent(event);
|
|
9194
|
+
if (!entry)
|
|
9195
|
+
return;
|
|
9196
|
+
if (showRepoContextMenu(event, entry, REPO_SIDEBAR_REF || "worktree", () => loadRepo()))
|
|
9197
|
+
markActive(entry.path);
|
|
9198
|
+
}
|
|
9199
|
+
function createMoveToTrashButton(path, onDeleted) {
|
|
9200
|
+
const button = document.createElement("button");
|
|
9201
|
+
button.type = "button";
|
|
9202
|
+
button.className = "gdp-btn gdp-btn-sm gdp-trash-path";
|
|
9203
|
+
button.textContent = "Move to Trash";
|
|
9204
|
+
button.addEventListener("click", async (event) => {
|
|
9205
|
+
event.stopPropagation();
|
|
9206
|
+
await requestMoveToTrash(path, onDeleted, { focusReturnTarget: button });
|
|
9207
|
+
});
|
|
9208
|
+
return button;
|
|
9209
|
+
}
|
|
8943
9210
|
function createOpenPathButton(path, kind, title = "open folder in OS") {
|
|
8944
9211
|
const button = document.createElement("button");
|
|
8945
9212
|
button.type = "button";
|
|
@@ -9130,69 +9397,82 @@ ${frontmatter.yaml}
|
|
|
9130
9397
|
if (meta.upload_enabled && (meta.ref === "worktree" || meta.ref === "")) {
|
|
9131
9398
|
listWrapper.appendChild(createRepoUploadPanel(meta.path || ""));
|
|
9132
9399
|
}
|
|
9400
|
+
const sortHost = document.createElement("div");
|
|
9401
|
+
sortHost.className = "gdp-repo-sort-host";
|
|
9133
9402
|
const list2 = document.createElement("div");
|
|
9134
9403
|
list2.className = "gdp-source-viewer gdp-repo-file-list";
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9139
|
-
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
|
|
9149
|
-
|
|
9150
|
-
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
|
|
9154
|
-
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
const icon = document.createElement("span");
|
|
9161
|
-
icon.className = entry.type === "tree" ? "dir-icon" : "d2h-icon-wrapper";
|
|
9162
|
-
if (entry.type === "tree")
|
|
9163
|
-
setFolderIcon(icon, true);
|
|
9164
|
-
else
|
|
9165
|
-
icon.innerHTML = fileEntryIcon();
|
|
9166
|
-
const name = document.createElement("span");
|
|
9167
|
-
name.className = "name";
|
|
9168
|
-
name.textContent = entry.name;
|
|
9169
|
-
const kind = document.createElement("span");
|
|
9170
|
-
kind.className = "kind";
|
|
9171
|
-
kind.textContent = entry.type === "tree" ? "directory" : entry.type === "commit" ? "submodule" : "file";
|
|
9172
|
-
row.append(icon, name, kind);
|
|
9173
|
-
row.addEventListener("click", () => {
|
|
9174
|
-
if (entry.type === "tree") {
|
|
9175
|
-
setRoute(repoRoute(meta.ref, entry.path));
|
|
9404
|
+
const renderRepoRows = (focusSortKey) => {
|
|
9405
|
+
sortHost.replaceChildren(createRepoSortHeader(renderRepoRows));
|
|
9406
|
+
if (focusSortKey) {
|
|
9407
|
+
sortHost.querySelector(`[data-repo-sort="${focusSortKey}"]`)?.focus();
|
|
9408
|
+
}
|
|
9409
|
+
list2.replaceChildren();
|
|
9410
|
+
if (meta.path) {
|
|
9411
|
+
const parent = meta.path.split("/").slice(0, -1).join("/");
|
|
9412
|
+
const row = document.createElement("button");
|
|
9413
|
+
row.type = "button";
|
|
9414
|
+
row.className = "gdp-repo-row parent";
|
|
9415
|
+
const parentIcon = document.createElement("span");
|
|
9416
|
+
parentIcon.className = "dir-icon";
|
|
9417
|
+
setFolderIcon(parentIcon, false);
|
|
9418
|
+
const parentName = document.createElement("span");
|
|
9419
|
+
parentName.className = "name";
|
|
9420
|
+
parentName.textContent = "..";
|
|
9421
|
+
const parentKind = document.createElement("span");
|
|
9422
|
+
parentKind.className = "meta";
|
|
9423
|
+
parentKind.textContent = "";
|
|
9424
|
+
const parentSize = document.createElement("span");
|
|
9425
|
+
parentSize.className = "size";
|
|
9426
|
+
row.append(parentIcon, parentName, parentKind, parentSize);
|
|
9427
|
+
row.addEventListener("click", () => {
|
|
9428
|
+
setRoute(repoRoute(meta.ref, parent));
|
|
9176
9429
|
loadRepo();
|
|
9177
|
-
}
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9430
|
+
});
|
|
9431
|
+
list2.appendChild(row);
|
|
9432
|
+
}
|
|
9433
|
+
sortedRepoEntries(meta.entries).forEach((entry) => {
|
|
9434
|
+
const row = document.createElement("button");
|
|
9435
|
+
row.type = "button";
|
|
9436
|
+
row.className = `gdp-repo-row ${entry.type}`;
|
|
9437
|
+
const icon = document.createElement("span");
|
|
9438
|
+
icon.className = entry.type === "tree" ? "dir-icon" : "d2h-icon-wrapper";
|
|
9439
|
+
if (entry.type === "tree")
|
|
9440
|
+
setFolderIcon(icon, true);
|
|
9441
|
+
else
|
|
9442
|
+
icon.innerHTML = fileEntryIcon();
|
|
9443
|
+
const name = document.createElement("span");
|
|
9444
|
+
name.className = "name";
|
|
9445
|
+
name.textContent = entry.name;
|
|
9446
|
+
const metaBlock = createRepoEntryMeta(entry);
|
|
9447
|
+
const size = createRepoEntrySize(entry);
|
|
9448
|
+
row.append(icon, name, metaBlock, size);
|
|
9449
|
+
row.addEventListener("click", () => {
|
|
9450
|
+
if (entry.type === "tree") {
|
|
9451
|
+
setRoute(repoRoute(meta.ref, entry.path));
|
|
9452
|
+
loadRepo();
|
|
9453
|
+
} else if (entry.type === "blob") {
|
|
9454
|
+
setRoute({
|
|
9455
|
+
screen: "file",
|
|
9456
|
+
path: entry.path,
|
|
9457
|
+
ref: meta.ref,
|
|
9458
|
+
view: "blob",
|
|
9459
|
+
range: currentRange()
|
|
9460
|
+
});
|
|
9461
|
+
renderStandaloneSource({ path: entry.path, ref: meta.ref });
|
|
9462
|
+
}
|
|
9463
|
+
});
|
|
9464
|
+
row.addEventListener("contextmenu", (event) => showRepoContextMenu(event, entry, meta.ref, () => loadRepo()));
|
|
9465
|
+
list2.appendChild(row);
|
|
9187
9466
|
});
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9467
|
+
if (!meta.entries.length) {
|
|
9468
|
+
const empty = document.createElement("div");
|
|
9469
|
+
empty.className = "gdp-repo-empty";
|
|
9470
|
+
empty.textContent = "No files in this directory.";
|
|
9471
|
+
list2.appendChild(empty);
|
|
9472
|
+
}
|
|
9473
|
+
};
|
|
9474
|
+
listWrapper.appendChild(sortHost);
|
|
9475
|
+
renderRepoRows();
|
|
9196
9476
|
listWrapper.appendChild(list2);
|
|
9197
9477
|
listCard.appendChild(listWrapper);
|
|
9198
9478
|
shell.appendChild(listCard);
|
|
@@ -9255,7 +9535,7 @@ ${frontmatter.yaml}
|
|
|
9255
9535
|
const params = new URLSearchParams;
|
|
9256
9536
|
params.set("ref", normalizedRef);
|
|
9257
9537
|
params.set("recursive", "1");
|
|
9258
|
-
|
|
9538
|
+
appendScopeParams(params);
|
|
9259
9539
|
REPO_SIDEBAR_LOAD_REF = normalizedRef;
|
|
9260
9540
|
const load2 = trackLoad(fetch(`/_tree?${params.toString()}`).then((r2) => {
|
|
9261
9541
|
if (!r2.ok)
|
|
@@ -9273,6 +9553,7 @@ ${frontmatter.yaml}
|
|
|
9273
9553
|
children_omitted: entry.children_omitted,
|
|
9274
9554
|
children_omitted_reason: entry.children_omitted_reason
|
|
9275
9555
|
}));
|
|
9556
|
+
REPO_SIDEBAR_REF = normalizedRef;
|
|
9276
9557
|
renderSidebar(files, (file) => {
|
|
9277
9558
|
if (file.type === "tree") {
|
|
9278
9559
|
setRoute(repoRoute(normalizedRef, file.path));
|
|
@@ -9288,7 +9569,6 @@ ${frontmatter.yaml}
|
|
|
9288
9569
|
});
|
|
9289
9570
|
renderStandaloneSource({ path: file.path, ref: normalizedRef });
|
|
9290
9571
|
});
|
|
9291
|
-
REPO_SIDEBAR_REF = normalizedRef;
|
|
9292
9572
|
activateRepoSidebarPath(currentPath);
|
|
9293
9573
|
}).catch(() => {
|
|
9294
9574
|
REPO_SIDEBAR_REF = null;
|
|
@@ -10335,6 +10615,117 @@ ${frontmatter.yaml}
|
|
|
10335
10615
|
}
|
|
10336
10616
|
return (unit === 0 ? String(value) : value.toFixed(value >= 10 ? 1 : 2).replace(/\.0+$/, "")) + " " + units[unit];
|
|
10337
10617
|
}
|
|
10618
|
+
function formatFileDate(value) {
|
|
10619
|
+
if (!value)
|
|
10620
|
+
return "";
|
|
10621
|
+
const date = new Date(value);
|
|
10622
|
+
if (Number.isNaN(date.getTime()))
|
|
10623
|
+
return "";
|
|
10624
|
+
return date.toLocaleString(undefined, {
|
|
10625
|
+
year: "numeric",
|
|
10626
|
+
month: "short",
|
|
10627
|
+
day: "numeric",
|
|
10628
|
+
hour: "2-digit",
|
|
10629
|
+
minute: "2-digit"
|
|
10630
|
+
});
|
|
10631
|
+
}
|
|
10632
|
+
function createRepoEntryMeta(entry) {
|
|
10633
|
+
const meta = document.createElement("span");
|
|
10634
|
+
meta.className = "meta";
|
|
10635
|
+
const updated = formatFileDate(entry.updated_at || entry.commit_updated_at);
|
|
10636
|
+
const created = formatFileDate(entry.created_at);
|
|
10637
|
+
if (entry.type === "tree" && updated) {
|
|
10638
|
+
meta.textContent = updated;
|
|
10639
|
+
if (created)
|
|
10640
|
+
meta.title = `Created ${created}`;
|
|
10641
|
+
return meta;
|
|
10642
|
+
}
|
|
10643
|
+
if (entry.type !== "blob") {
|
|
10644
|
+
meta.textContent = "-";
|
|
10645
|
+
return meta;
|
|
10646
|
+
}
|
|
10647
|
+
meta.textContent = updated ? updated : created ? created : "-";
|
|
10648
|
+
if (created)
|
|
10649
|
+
meta.title = `Created ${created}`;
|
|
10650
|
+
return meta;
|
|
10651
|
+
}
|
|
10652
|
+
function createRepoEntrySize(entry) {
|
|
10653
|
+
const size = document.createElement("span");
|
|
10654
|
+
size.className = "size";
|
|
10655
|
+
size.textContent = entry.type === "blob" && entry.size != null ? formatBytes(entry.size) : "";
|
|
10656
|
+
return size;
|
|
10657
|
+
}
|
|
10658
|
+
function repoEntryUpdatedTime(entry) {
|
|
10659
|
+
const raw = entry.updated_at || entry.commit_updated_at || entry.created_at;
|
|
10660
|
+
if (!raw)
|
|
10661
|
+
return -1;
|
|
10662
|
+
const time = new Date(raw).getTime();
|
|
10663
|
+
return Number.isNaN(time) ? -1 : time;
|
|
10664
|
+
}
|
|
10665
|
+
function sortedRepoEntries(entries) {
|
|
10666
|
+
const direction = REPO_SORT.direction === "asc" ? 1 : -1;
|
|
10667
|
+
return [...entries].sort((a2, b2) => {
|
|
10668
|
+
if (REPO_SORT.key === "name" && a2.type !== b2.type) {
|
|
10669
|
+
if (a2.type === "tree")
|
|
10670
|
+
return -1;
|
|
10671
|
+
if (b2.type === "tree")
|
|
10672
|
+
return 1;
|
|
10673
|
+
}
|
|
10674
|
+
let result = 0;
|
|
10675
|
+
if (REPO_SORT.key === "updated") {
|
|
10676
|
+
const aTime = repoEntryUpdatedTime(a2);
|
|
10677
|
+
const bTime = repoEntryUpdatedTime(b2);
|
|
10678
|
+
if (aTime < 0 && bTime >= 0)
|
|
10679
|
+
return 1;
|
|
10680
|
+
if (bTime < 0 && aTime >= 0)
|
|
10681
|
+
return -1;
|
|
10682
|
+
result = aTime - bTime;
|
|
10683
|
+
} else if (REPO_SORT.key === "size") {
|
|
10684
|
+
if (a2.size == null && b2.size != null)
|
|
10685
|
+
return 1;
|
|
10686
|
+
if (b2.size == null && a2.size != null)
|
|
10687
|
+
return -1;
|
|
10688
|
+
result = (a2.size ?? 0) - (b2.size ?? 0);
|
|
10689
|
+
} else {
|
|
10690
|
+
result = a2.name.localeCompare(b2.name);
|
|
10691
|
+
}
|
|
10692
|
+
if (result === 0)
|
|
10693
|
+
result = a2.name.localeCompare(b2.name);
|
|
10694
|
+
return result * direction;
|
|
10695
|
+
});
|
|
10696
|
+
}
|
|
10697
|
+
function createRepoSortHeader(onSortChange) {
|
|
10698
|
+
const header = document.createElement("div");
|
|
10699
|
+
header.className = "gdp-repo-sort-header";
|
|
10700
|
+
const spacer = document.createElement("span");
|
|
10701
|
+
spacer.className = "gdp-repo-sort-spacer";
|
|
10702
|
+
header.appendChild(spacer);
|
|
10703
|
+
const columns = [
|
|
10704
|
+
{ key: "name", label: "Name" },
|
|
10705
|
+
{ key: "updated", label: "Updated" },
|
|
10706
|
+
{ key: "size", label: "Size" }
|
|
10707
|
+
];
|
|
10708
|
+
columns.forEach((column) => {
|
|
10709
|
+
const button = document.createElement("button");
|
|
10710
|
+
button.type = "button";
|
|
10711
|
+
button.dataset.repoSort = column.key;
|
|
10712
|
+
button.textContent = column.label + (REPO_SORT.key === column.key ? REPO_SORT.direction === "asc" ? " ↑" : " ↓" : "");
|
|
10713
|
+
button.className = REPO_SORT.key === column.key ? "active" : "";
|
|
10714
|
+
button.addEventListener("click", () => {
|
|
10715
|
+
if (REPO_SORT.key === column.key) {
|
|
10716
|
+
REPO_SORT.direction = REPO_SORT.direction === "asc" ? "desc" : "asc";
|
|
10717
|
+
} else {
|
|
10718
|
+
REPO_SORT = {
|
|
10719
|
+
key: column.key,
|
|
10720
|
+
direction: column.key === "name" ? "asc" : "desc"
|
|
10721
|
+
};
|
|
10722
|
+
}
|
|
10723
|
+
onSortChange(column.key);
|
|
10724
|
+
});
|
|
10725
|
+
header.appendChild(button);
|
|
10726
|
+
});
|
|
10727
|
+
return header;
|
|
10728
|
+
}
|
|
10338
10729
|
function humanFileKind(path, mime, fallback) {
|
|
10339
10730
|
const ext = (path.split(".").pop() || "").toLowerCase();
|
|
10340
10731
|
if (ext === "png")
|
|
@@ -10392,12 +10783,41 @@ ${frontmatter.yaml}
|
|
|
10392
10783
|
const size = rawSize == null ? NaN : Number(rawSize);
|
|
10393
10784
|
return {
|
|
10394
10785
|
size: rawSize != null && Number.isFinite(size) ? size : undefined,
|
|
10395
|
-
type: res.headers.get("content-type") || undefined
|
|
10786
|
+
type: res.headers.get("content-type") || undefined,
|
|
10787
|
+
created_at: res.headers.get("x-code-viewer-created-at") || undefined,
|
|
10788
|
+
updated_at: res.headers.get("x-code-viewer-updated-at") || undefined,
|
|
10789
|
+
commit_updated_at: res.headers.get("x-code-viewer-commit-updated-at") || undefined
|
|
10396
10790
|
};
|
|
10397
10791
|
} catch {
|
|
10398
10792
|
return {};
|
|
10399
10793
|
}
|
|
10400
10794
|
}
|
|
10795
|
+
function createFileDetailMeta(target, meta) {
|
|
10796
|
+
const wrap = document.createElement("div");
|
|
10797
|
+
wrap.className = "gdp-file-detail-meta";
|
|
10798
|
+
const addItem = (label, value) => {
|
|
10799
|
+
if (!value)
|
|
10800
|
+
return;
|
|
10801
|
+
const item = document.createElement("span");
|
|
10802
|
+
item.className = "gdp-file-detail-meta-item";
|
|
10803
|
+
const labelEl = document.createElement("span");
|
|
10804
|
+
labelEl.className = "label";
|
|
10805
|
+
labelEl.textContent = label;
|
|
10806
|
+
const valueEl = document.createElement("span");
|
|
10807
|
+
valueEl.className = "value";
|
|
10808
|
+
valueEl.textContent = value;
|
|
10809
|
+
item.append(labelEl, valueEl);
|
|
10810
|
+
wrap.appendChild(item);
|
|
10811
|
+
};
|
|
10812
|
+
addItem("Size", meta.size == null ? "" : formatBytes(meta.size));
|
|
10813
|
+
addItem("Updated", formatFileDate(meta.updated_at || meta.commit_updated_at));
|
|
10814
|
+
addItem("Created", formatFileDate(meta.created_at));
|
|
10815
|
+
if (!wrap.childElementCount) {
|
|
10816
|
+
wrap.hidden = true;
|
|
10817
|
+
wrap.dataset.path = target.path;
|
|
10818
|
+
}
|
|
10819
|
+
return wrap;
|
|
10820
|
+
}
|
|
10401
10821
|
function createSourceFileInfo(target, kind) {
|
|
10402
10822
|
const info = document.createElement("div");
|
|
10403
10823
|
info.className = "gdp-source-file-info";
|
|
@@ -11423,6 +11843,18 @@ ${frontmatter.yaml}
|
|
|
11423
11843
|
name.appendChild(copy);
|
|
11424
11844
|
name.appendChild(createOpenPathButton(target.path, "file-parent", "open parent folder in OS"));
|
|
11425
11845
|
header.appendChild(name);
|
|
11846
|
+
if (repoTarget && canTrashWorktreeRef(repoTarget)) {
|
|
11847
|
+
header.appendChild(createMoveToTrashButton(target.path, () => {
|
|
11848
|
+
const parent = target.path.split("/").slice(0, -1).join("/");
|
|
11849
|
+
setRoute(repoRoute(repoTarget, parent));
|
|
11850
|
+
loadRepo();
|
|
11851
|
+
}));
|
|
11852
|
+
}
|
|
11853
|
+
loadRawFileInfo(target).then((meta) => {
|
|
11854
|
+
if (req !== SOURCE_REQ_SEQ || !sourceTargetsEqual(sourceTargetFromRoute(), target))
|
|
11855
|
+
return;
|
|
11856
|
+
header.appendChild(createFileDetailMeta(target, meta));
|
|
11857
|
+
});
|
|
11426
11858
|
if (!repoTarget) {
|
|
11427
11859
|
const back = document.createElement("button");
|
|
11428
11860
|
back.type = "button";
|
|
@@ -12620,7 +13052,7 @@ ${frontmatter.yaml}
|
|
|
12620
13052
|
return cached;
|
|
12621
13053
|
const params = new URLSearchParams;
|
|
12622
13054
|
params.set("ref", ref);
|
|
12623
|
-
|
|
13055
|
+
appendScopeParams(params);
|
|
12624
13056
|
const res = await trackLoad(fetch(`/_files?${params.toString()}`).then((r2) => {
|
|
12625
13057
|
if (!r2.ok)
|
|
12626
13058
|
throw new Error("failed to load files");
|
|
@@ -12724,7 +13156,7 @@ ${frontmatter.yaml}
|
|
|
12724
13156
|
params.set("max", "200");
|
|
12725
13157
|
if (state.grepRegex)
|
|
12726
13158
|
params.set("regex", "1");
|
|
12727
|
-
|
|
13159
|
+
appendScopeParams(params);
|
|
12728
13160
|
if (source === "diff") {
|
|
12729
13161
|
for (const file of state.diffSnapshot)
|
|
12730
13162
|
params.append("path", file.path);
|
|
@@ -13015,10 +13447,19 @@ ${frontmatter.yaml}
|
|
|
13015
13447
|
document.addEventListener("keydown", handleVirtualSourcePagingKeydown, {
|
|
13016
13448
|
capture: true
|
|
13017
13449
|
});
|
|
13018
|
-
document.addEventListener("
|
|
13450
|
+
document.addEventListener("click", closeRepoContextMenu);
|
|
13451
|
+
$("#filelist").addEventListener("contextmenu", handleSidebarContextMenu);
|
|
13452
|
+
document.addEventListener("keydown", async (e2) => {
|
|
13453
|
+
if (e2.key === "Escape")
|
|
13454
|
+
closeRepoContextMenu();
|
|
13019
13455
|
if (e2.__gdpVirtualSourcePagingHandled)
|
|
13020
13456
|
return;
|
|
13021
13457
|
const targetEl = e2.target;
|
|
13458
|
+
if ((e2.ctrlKey || e2.metaKey) && !e2.shiftKey && !e2.altKey && e2.key.toLowerCase() === "z" && !isEditableKeyTarget(targetEl)) {
|
|
13459
|
+
if (await undoLastAction())
|
|
13460
|
+
e2.preventDefault();
|
|
13461
|
+
return;
|
|
13462
|
+
}
|
|
13022
13463
|
if ((e2.ctrlKey || e2.metaKey) && e2.key.toLowerCase() === "f" && !isEditableKeyTarget(targetEl)) {
|
|
13023
13464
|
if (openVirtualSourceSearchFromKeyboard(targetEl)) {
|
|
13024
13465
|
e2.preventDefault();
|
|
@@ -13053,7 +13494,7 @@ ${frontmatter.yaml}
|
|
|
13053
13494
|
params.set("ref", STATE.route.ref || "worktree");
|
|
13054
13495
|
if (STATE.route.path)
|
|
13055
13496
|
params.set("path", STATE.route.path);
|
|
13056
|
-
|
|
13497
|
+
appendScopeParams(params);
|
|
13057
13498
|
return trackLoad(fetch(`/_tree?${params.toString()}`).then((r2) => {
|
|
13058
13499
|
if (!r2.ok)
|
|
13059
13500
|
throw new Error("failed to load repository tree");
|