From 50bf7087fa64c01b78384364c05819f1a8700918 Mon Sep 17 00:00:00 2001 From: bytedream Date: Thu, 29 May 2025 01:59:43 +0200 Subject: [PATCH 01/13] Open new tab when clicking file tree with mouse wheel --- web_src/js/components/ViewFileTree.vue | 6 +++++- web_src/js/components/ViewFileTreeItem.vue | 21 ++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/web_src/js/components/ViewFileTree.vue b/web_src/js/components/ViewFileTree.vue index c692142792754..bdbf71a04e975 100644 --- a/web_src/js/components/ViewFileTree.vue +++ b/web_src/js/components/ViewFileTree.vue @@ -37,8 +37,12 @@ async function loadViewContent(url: string) { document.querySelector('.repo-view-content').innerHTML = await response.text(); } -async function navigateTreeView(treePath: string) { +async function navigateTreeView(treePath: string, newTab: boolean) { const url = `${props.repoLink}/src/${props.currentRefNameSubURL}/${pathEscapeSegments(treePath)}`; + if (newTab) { + window.open(url, '_blank'); + return; + } window.history.pushState({treePath, url}, null, url); selectedItem.value = treePath; await loadViewContent(url); diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index c39fa1f4aef16..bb3ab8fbeb40a 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -14,7 +14,7 @@ type Item = { const props = defineProps<{ item: Item, - navigateViewContent:(treePath: string) => void, + navigateViewContent:(treePath: string, newTab: boolean) => void, loadChildren:(treePath: string, subPath?: string) => Promise, selectedItem?: string, }>(); @@ -35,13 +35,13 @@ const doLoadChildren = async () => { } }; -const doLoadDirContent = () => { - doLoadChildren(); - props.navigateViewContent(props.item.fullPath); +const doLoadDirContent = (newTab: boolean) => { + if (!newTab) doLoadChildren(); + props.navigateViewContent(props.item.fullPath, newTab); }; -const doLoadFileContent = () => { - props.navigateViewContent(props.item.fullPath); +const doLoadFileContent = (newTab: boolean) => { + props.navigateViewContent(props.item.fullPath, newTab); }; const doGotoSubModule = () => { @@ -67,7 +67,8 @@ const doGotoSubModule = () => { v-else-if="item.entryMode === 'symlink'" class="tree-item type-symlink" :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" - @click.stop="doLoadFileContent" + @click.stop="doLoadFileContent(false)" + @auxclick.stop="doLoadFileContent(true)" >
@@ -80,7 +81,8 @@ const doGotoSubModule = () => { v-else-if="item.entryMode !== 'tree'" class="tree-item type-file" :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" - @click.stop="doLoadFileContent" + @click.stop="doLoadFileContent(false)" + @auxclick.stop="doLoadFileContent(true)" >
@@ -93,7 +95,8 @@ const doGotoSubModule = () => { v-else class="tree-item type-directory" :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" - @click.stop="doLoadDirContent" + @click.stop="doLoadDirContent(false)" + @auxclick.stop="doLoadDirContent(true)" >
From 83e925a6051c860f57623a81fbd2028d7f1547fb Mon Sep 17 00:00:00 2001 From: bytedream Date: Thu, 29 May 2025 02:20:57 +0200 Subject: [PATCH 02/13] Use own function instead --- web_src/js/components/ViewFileTree.vue | 2 +- web_src/js/components/ViewFileTreeItem.vue | 28 ++++++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/web_src/js/components/ViewFileTree.vue b/web_src/js/components/ViewFileTree.vue index bdbf71a04e975..0e1ea7f59d3b0 100644 --- a/web_src/js/components/ViewFileTree.vue +++ b/web_src/js/components/ViewFileTree.vue @@ -37,7 +37,7 @@ async function loadViewContent(url: string) { document.querySelector('.repo-view-content').innerHTML = await response.text(); } -async function navigateTreeView(treePath: string, newTab: boolean) { +async function navigateTreeView(treePath: string, newTab?: boolean) { const url = `${props.repoLink}/src/${props.currentRefNameSubURL}/${pathEscapeSegments(treePath)}`; if (newTab) { window.open(url, '_blank'); diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index bb3ab8fbeb40a..5b2a4e577bfa9 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -14,7 +14,7 @@ type Item = { const props = defineProps<{ item: Item, - navigateViewContent:(treePath: string, newTab: boolean) => void, + navigateViewContent:(treePath: string, newTab?: boolean) => void, loadChildren:(treePath: string, subPath?: string) => Promise, selectedItem?: string, }>(); @@ -35,13 +35,17 @@ const doLoadChildren = async () => { } }; -const doLoadDirContent = (newTab: boolean) => { - if (!newTab) doLoadChildren(); - props.navigateViewContent(props.item.fullPath, newTab); +const doLoadDirContent = () => { + doLoadChildren(); + props.navigateViewContent(props.item.fullPath); }; -const doLoadFileContent = (newTab: boolean) => { - props.navigateViewContent(props.item.fullPath, newTab); +const doLoadFileContent = () => { + props.navigateViewContent(props.item.fullPath); +}; + +const doOpenContentInNewTab = () => { + props.navigateViewContent(props.item.fullPath, true); }; const doGotoSubModule = () => { @@ -67,8 +71,8 @@ const doGotoSubModule = () => { v-else-if="item.entryMode === 'symlink'" class="tree-item type-symlink" :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" - @click.stop="doLoadFileContent(false)" - @auxclick.stop="doLoadFileContent(true)" + @click.stop="doLoadFileContent" + @auxclick.stop="doOpenContentInNewTab" >
@@ -81,8 +85,8 @@ const doGotoSubModule = () => { v-else-if="item.entryMode !== 'tree'" class="tree-item type-file" :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" - @click.stop="doLoadFileContent(false)" - @auxclick.stop="doLoadFileContent(true)" + @click.stop="doLoadFileContent" + @auxclick.stop="doOpenContentInNewTab" >
@@ -95,8 +99,8 @@ const doGotoSubModule = () => { v-else class="tree-item type-directory" :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" - @click.stop="doLoadDirContent(false)" - @auxclick.stop="doLoadDirContent(true)" + @click.stop="doLoadDirContent" + @auxclick.stop="doOpenContentInNewTab" >
From 91069cf5382365362f94a5608e282f6993514afa Mon Sep 17 00:00:00 2001 From: bytedream Date: Sun, 15 Jun 2025 16:21:58 +0200 Subject: [PATCH 03/13] use click.middle instead of auxclick --- web_src/js/components/ViewFileTreeItem.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 5b2a4e577bfa9..cd1969e58c653 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -72,7 +72,7 @@ const doGotoSubModule = () => { :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" @click.stop="doLoadFileContent" - @auxclick.stop="doOpenContentInNewTab" + @click.middle.stop="doOpenContentInNewTab" >
@@ -86,7 +86,7 @@ const doGotoSubModule = () => { :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" @click.stop="doLoadFileContent" - @auxclick.stop="doOpenContentInNewTab" + @click.middle.stop="doOpenContentInNewTab" >
@@ -100,7 +100,7 @@ const doGotoSubModule = () => { :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" @click.stop="doLoadDirContent" - @auxclick.stop="doOpenContentInNewTab" + @click.middle.stop="doOpenContentInNewTab" >
From 2b5e11981656ed4c0db17232dc786ba71838143d Mon Sep 17 00:00:00 2001 From: bytedream Date: Mon, 16 Jun 2025 12:36:24 +0200 Subject: [PATCH 04/13] also check if ctrl key was pressed --- web_src/js/components/ViewFileTreeItem.vue | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index cd1969e58c653..8ffe3e464f68a 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -40,12 +40,12 @@ const doLoadDirContent = () => { props.navigateViewContent(props.item.fullPath); }; -const doLoadFileContent = () => { - props.navigateViewContent(props.item.fullPath); -}; - -const doOpenContentInNewTab = () => { - props.navigateViewContent(props.item.fullPath, true); +const doLoadFileContent = (event: MouseEvent) => { + // open the file in a new tab if either + // - the auxiliary button (mouse wheel button) is the origin of the click + // - the ctrl key was pressed while clicking + const openNewTab = event.button === 1 || event.ctrlKey; + props.navigateViewContent(props.item.fullPath, openNewTab); }; const doGotoSubModule = () => { @@ -72,7 +72,7 @@ const doGotoSubModule = () => { :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" @click.stop="doLoadFileContent" - @click.middle.stop="doOpenContentInNewTab" + @click.middle.stop="doLoadFileContent" >
@@ -86,7 +86,7 @@ const doGotoSubModule = () => { :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" @click.stop="doLoadFileContent" - @click.middle.stop="doOpenContentInNewTab" + @click.middle.stop="doLoadFileContent" >
@@ -100,7 +100,7 @@ const doGotoSubModule = () => { :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" @click.stop="doLoadDirContent" - @click.middle.stop="doOpenContentInNewTab" + @click.middle.stop="doLoadFileContent" >
From 06ac1c9f1371c321b4850cc967cdbf750b9d640d Mon Sep 17 00:00:00 2001 From: bytedream Date: Mon, 16 Jun 2025 12:38:14 +0200 Subject: [PATCH 05/13] update comment --- web_src/js/components/ViewFileTreeItem.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 8ffe3e464f68a..696d234e10f18 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -42,7 +42,7 @@ const doLoadDirContent = () => { const doLoadFileContent = (event: MouseEvent) => { // open the file in a new tab if either - // - the auxiliary button (mouse wheel button) is the origin of the click + // - the auxiliary button (usually the mouse wheel button) is the origin of the click // - the ctrl key was pressed while clicking const openNewTab = event.button === 1 || event.ctrlKey; props.navigateViewContent(props.item.fullPath, openNewTab); From 10d947114617c395b787c874d65f0d029982a2a3 Mon Sep 17 00:00:00 2001 From: bytedream Date: Mon, 16 Jun 2025 13:53:48 +0200 Subject: [PATCH 06/13] check meta key in addition to ctrl --- web_src/js/components/ViewFileTreeItem.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 696d234e10f18..8cd9d36b57295 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -43,8 +43,8 @@ const doLoadDirContent = () => { const doLoadFileContent = (event: MouseEvent) => { // open the file in a new tab if either // - the auxiliary button (usually the mouse wheel button) is the origin of the click - // - the ctrl key was pressed while clicking - const openNewTab = event.button === 1 || event.ctrlKey; + // - the ctrl key or meta key (for mac support) was pressed while clicking + const openNewTab = event.button === 1 || event.ctrlKey || event.metaKey; props.navigateViewContent(props.item.fullPath, openNewTab); }; From 9c4a8e2da7cd73cd605c700c8953b7a18c85c6aa Mon Sep 17 00:00:00 2001 From: bytedream Date: Mon, 16 Jun 2025 14:02:46 +0200 Subject: [PATCH 07/13] add aux click check to doLoadDirContent --- web_src/js/components/ViewFileTreeItem.vue | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 8cd9d36b57295..42c1978a185cd 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -35,15 +35,16 @@ const doLoadChildren = async () => { } }; -const doLoadDirContent = () => { - doLoadChildren(); - props.navigateViewContent(props.item.fullPath); +const doLoadDirContent = (event: MouseEvent) => { + // open the directory in a new tab if either + // - the auxiliary button (usually the mouse wheel button) is the origin of the click + // - the ctrl key or meta key (for mac support) was pressed while clicking + const openNewTab = event.button === 1 || event.ctrlKey || event.metaKey; + if (!openNewTab) doLoadChildren(); + props.navigateViewContent(props.item.fullPath, openNewTab); }; const doLoadFileContent = (event: MouseEvent) => { - // open the file in a new tab if either - // - the auxiliary button (usually the mouse wheel button) is the origin of the click - // - the ctrl key or meta key (for mac support) was pressed while clicking const openNewTab = event.button === 1 || event.ctrlKey || event.metaKey; props.navigateViewContent(props.item.fullPath, openNewTab); }; @@ -100,7 +101,7 @@ const doGotoSubModule = () => { :class="{'selected': selectedItem === item.fullPath}" :title="item.entryName" @click.stop="doLoadDirContent" - @click.middle.stop="doLoadFileContent" + @click.middle.stop="doLoadDirContent" >
From 9915581f4ce8111ddef27bb4765fdae6bed2a018 Mon Sep 17 00:00:00 2001 From: bytedream Date: Mon, 16 Jun 2025 14:46:54 +0200 Subject: [PATCH 08/13] add sub module aux click support --- web_src/js/components/ViewFileTreeItem.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 42c1978a185cd..769888b651b07 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -49,7 +49,12 @@ const doLoadFileContent = (event: MouseEvent) => { props.navigateViewContent(props.item.fullPath, openNewTab); }; -const doGotoSubModule = () => { +const doGotoSubModule = (event: MouseEvent) => { + const openNewTab = event.button === 1 || event.ctrlKey || event.metaKey; + if (openNewTab) { + window.open(props.item.submoduleUrl, '_blank'); + return; + } location.href = props.item.submoduleUrl; }; @@ -60,6 +65,7 @@ const doGotoSubModule = () => { v-if="item.entryMode === 'commit'" class="tree-item type-submodule" :title="item.entryName" @click.stop="doGotoSubModule" + @click.middle.stop="doGotoSubModule" >
From ee2f52a1c3bf463bda3cfb061c5c44b257626925 Mon Sep 17 00:00:00 2001 From: bytedream Date: Wed, 18 Jun 2025 18:04:57 +0200 Subject: [PATCH 09/13] use `a` for file tree files --- web_src/js/components/ViewFileTree.vue | 14 ++--- web_src/js/components/ViewFileTreeItem.vue | 67 +++++++++++----------- 2 files changed, 40 insertions(+), 41 deletions(-) diff --git a/web_src/js/components/ViewFileTree.vue b/web_src/js/components/ViewFileTree.vue index 0e1ea7f59d3b0..b1e57752acbd5 100644 --- a/web_src/js/components/ViewFileTree.vue +++ b/web_src/js/components/ViewFileTree.vue @@ -37,17 +37,17 @@ async function loadViewContent(url: string) { document.querySelector('.repo-view-content').innerHTML = await response.text(); } -async function navigateTreeView(treePath: string, newTab?: boolean) { - const url = `${props.repoLink}/src/${props.currentRefNameSubURL}/${pathEscapeSegments(treePath)}`; - if (newTab) { - window.open(url, '_blank'); - return; - } +async function navigateTreeView(treePath: string) { + const url = getWebUrl(treePath); window.history.pushState({treePath, url}, null, url); selectedItem.value = treePath; await loadViewContent(url); } +function getWebUrl(treePath: string) { + return `${props.repoLink}/src/${props.currentRefNameSubURL}/${pathEscapeSegments(treePath)}`; +} + onMounted(async () => { selectedItem.value = props.treePath; files.value = await loadChildren('', props.treePath); @@ -62,7 +62,7 @@ onMounted(async () => { diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 769888b651b07..9474141be5759 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -14,8 +14,9 @@ type Item = { const props = defineProps<{ item: Item, - navigateViewContent:(treePath: string, newTab?: boolean) => void, + navigateViewContent:(treePath: string) => void, loadChildren:(treePath: string, subPath?: string) => Promise, + getWebUrl:(treePath: string) => string, selectedItem?: string, }>(); @@ -23,7 +24,11 @@ const isLoading = ref(false); const children = ref(props.item.children); const collapsed = ref(!props.item.children); -const doLoadChildren = async () => { +const doLoadChildren = async (e?: MouseEvent) => { + // the event is only not undefined if the user explicitly clicked on the directory item toggle. the preventDefault + // stops the event from bubbling up and causing a directory content load + e?.preventDefault(); + collapsed.value = !collapsed.value; if (!collapsed.value && props.loadChildren) { isLoading.value = true; @@ -35,37 +40,29 @@ const doLoadChildren = async () => { } }; -const doLoadDirContent = (event: MouseEvent) => { - // open the directory in a new tab if either - // - the auxiliary button (usually the mouse wheel button) is the origin of the click - // - the ctrl key or meta key (for mac support) was pressed while clicking - const openNewTab = event.button === 1 || event.ctrlKey || event.metaKey; - if (!openNewTab) doLoadChildren(); - props.navigateViewContent(props.item.fullPath, openNewTab); -}; +const doLoadDirContent = (e: MouseEvent) => { + // only load the directory content without a window refresh if the user didn't press any special key + if (e.button !== 0 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) return; + e.preventDefault(); -const doLoadFileContent = (event: MouseEvent) => { - const openNewTab = event.button === 1 || event.ctrlKey || event.metaKey; - props.navigateViewContent(props.item.fullPath, openNewTab); + doLoadChildren(); + props.navigateViewContent(props.item.fullPath); }; -const doGotoSubModule = (event: MouseEvent) => { - const openNewTab = event.button === 1 || event.ctrlKey || event.metaKey; - if (openNewTab) { - window.open(props.item.submoduleUrl, '_blank'); - return; - } - location.href = props.item.submoduleUrl; +const doLoadFileContent = (e: MouseEvent) => { + if (e.button !== 0 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) return; + e.preventDefault(); + + props.navigateViewContent(props.item.fullPath); };