Skip to content

Commit 156de30

Browse files
committed
refactor
1 parent 7914f27 commit 156de30

File tree

4 files changed

+66
-61
lines changed

4 files changed

+66
-61
lines changed

web_src/js/components/DiffFileTree.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ function updateState(visible: boolean) {
6060
</script>
6161

6262
<template>
63+
<!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->
6364
<div v-if="store.fileTreeIsVisible" class="diff-file-tree-items">
64-
<!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->
6565
<DiffFileTreeItem v-for="item in store.diffFileTree.TreeRoot.Children" :key="item.FullName" :item="item"/>
6666
</div>
6767
</template>

web_src/js/components/ViewFileTree.vue

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
<script lang="ts" setup>
22
import ViewFileTreeItem from './ViewFileTreeItem.vue';
33
import {onMounted, ref} from 'vue';
4-
import {pathEscapeSegments} from '../utils/url.ts';
5-
import {GET} from '../modules/fetch.ts';
6-
import {createElementFromHTML} from '../utils/dom.ts';
4+
import {createViewFileTreeStore} from './ViewFileTreeStore.ts';
75
86
const elRoot = ref<HTMLElement | null>(null);
97
@@ -13,56 +11,20 @@ const props = defineProps({
1311
currentRefNameSubURL: {type: String, required: true},
1412
});
1513
16-
const files = ref([]);
17-
const selectedItem = ref('');
18-
19-
async function loadChildren(treePath: string, subPath: string = '') {
20-
const response = await GET(`${props.repoLink}/tree-view/${props.currentRefNameSubURL}/${pathEscapeSegments(treePath)}?sub_path=${encodeURIComponent(subPath)}`);
21-
const json = await response.json();
22-
const poolSvgs = [];
23-
for (const [svgId, svgContent] of Object.entries(json.renderedIconPool ?? {})) {
24-
if (!document.querySelector(`.global-svg-icon-pool #${svgId}`)) poolSvgs.push(svgContent);
25-
}
26-
if (poolSvgs.length) {
27-
const svgContainer = createElementFromHTML('<div class="global-svg-icon-pool tw-hidden"></div>');
28-
svgContainer.innerHTML = poolSvgs.join('');
29-
document.body.append(svgContainer);
30-
}
31-
return json.fileTreeNodes ?? null;
32-
}
33-
34-
async function loadViewContent(url: string) {
35-
url = url.includes('?') ? url.replace('?', '?only_content=true') : `${url}?only_content=true`;
36-
const response = await GET(url);
37-
document.querySelector('.repo-view-content').innerHTML = await response.text();
38-
}
39-
40-
async function navigateTreeView(treePath: string) {
41-
const url = getWebUrl(treePath);
42-
window.history.pushState({treePath, url}, null, url);
43-
selectedItem.value = treePath;
44-
await loadViewContent(url);
45-
}
46-
47-
function getWebUrl(treePath: string) {
48-
return `${props.repoLink}/src/${props.currentRefNameSubURL}/${pathEscapeSegments(treePath)}`;
49-
}
50-
14+
const store = createViewFileTreeStore(props);
5115
onMounted(async () => {
52-
selectedItem.value = props.treePath;
53-
files.value = await loadChildren('', props.treePath);
16+
store.rootFiles = await store.loadChildren('', props.treePath);
5417
elRoot.value.closest('.is-loading')?.classList?.remove('is-loading');
5518
window.addEventListener('popstate', (e) => {
56-
selectedItem.value = e.state?.treePath || '';
57-
if (e.state?.url) loadViewContent(e.state.url);
19+
store.selectedItem = e.state?.treePath || '';
20+
if (e.state?.url) store.loadViewContent(e.state.url);
5821
});
5922
});
6023
</script>
6124

6225
<template>
6326
<div class="view-file-tree-items" ref="elRoot">
64-
<!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->
65-
<ViewFileTreeItem v-for="item in files" :key="item.name" :item="item" :selected-item="selectedItem" :get-web-url="getWebUrl" :navigate-view-content="navigateTreeView" :load-children="loadChildren"/>
27+
<ViewFileTreeItem v-for="item in store.rootFiles" :key="item.name" :item="item" :store="store"/>
6628
</div>
6729
</template>
6830

web_src/js/components/ViewFileTreeItem.vue

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import {SvgIcon} from '../svg.ts';
33
import {isPlainClick} from '../utils/dom.ts';
44
import {ref} from 'vue';
5+
import {type createViewFileTreeStore} from './ViewFileTreeStore.ts';
56
67
type Item = {
78
entryName: string;
@@ -15,12 +16,10 @@ type Item = {
1516
1617
const props = defineProps<{
1718
item: Item,
18-
navigateViewContent:(treePath: string) => void,
19-
loadChildren:(treePath: string, subPath?: string) => Promise<Item[]>,
20-
getWebUrl:(treePath: string) => string,
21-
selectedItem?: string,
19+
store: ReturnType<typeof createViewFileTreeStore>
2220
}>();
2321
22+
const store = props.store;
2423
const isLoading = ref(false);
2524
const children = ref(props.item.children);
2625
const collapsed = ref(!props.item.children);
@@ -31,10 +30,10 @@ const doLoadChildren = async (e: MouseEvent | null) => {
3130
e?.preventDefault();
3231
3332
collapsed.value = !collapsed.value;
34-
if (!collapsed.value && props.loadChildren) {
33+
if (!collapsed.value) {
3534
isLoading.value = true;
3635
try {
37-
children.value = await props.loadChildren(props.item.fullPath);
36+
children.value = await store.loadChildren(props.item.fullPath);
3837
} finally {
3938
isLoading.value = false;
4039
}
@@ -47,14 +46,14 @@ const doLoadDirContent = (e: MouseEvent) => {
4746
e.preventDefault();
4847
4948
doLoadChildren(null);
50-
props.navigateViewContent(props.item.fullPath);
49+
store.navigateTreeView(props.item.fullPath);
5150
};
5251
5352
const doLoadFileContent = (e: MouseEvent) => {
5453
if (!isPlainClick(e)) return;
5554
e.preventDefault();
5655
57-
props.navigateViewContent(props.item.fullPath);
56+
store.navigateTreeView(props.item.fullPath);
5857
};
5958
</script>
6059

@@ -63,7 +62,7 @@ const doLoadFileContent = (e: MouseEvent) => {
6362
<a
6463
v-if="item.entryMode === 'commit'" class="tree-item type-submodule silenced"
6564
:title="item.entryName"
66-
:href="getWebUrl(item.fullPath)"
65+
:href="store.getWebUrl(item.fullPath)"
6766
>
6867
<!-- submodule -->
6968
<div class="item-content">
@@ -74,9 +73,9 @@ const doLoadFileContent = (e: MouseEvent) => {
7473
</a>
7574
<a
7675
v-else-if="item.entryMode === 'symlink'" class="tree-item type-symlink silenced"
77-
:class="{'selected': selectedItem === item.fullPath}"
76+
:class="{'selected': store.selectedItem === item.fullPath}"
7877
:title="item.entryName"
79-
:href="getWebUrl(item.fullPath)"
78+
:href="store.getWebUrl(item.fullPath)"
8079
@click.stop="doLoadFileContent"
8180
>
8281
<!-- symlink -->
@@ -88,9 +87,9 @@ const doLoadFileContent = (e: MouseEvent) => {
8887
</a>
8988
<a
9089
v-else-if="item.entryMode !== 'tree'" class="tree-item type-file silenced"
91-
:class="{'selected': selectedItem === item.fullPath}"
90+
:class="{'selected': store.selectedItem === item.fullPath}"
9291
:title="item.entryName"
93-
:href="getWebUrl(item.fullPath)"
92+
:href="store.getWebUrl(item.fullPath)"
9493
@click.stop="doLoadFileContent"
9594
>
9695
<!-- file -->
@@ -102,9 +101,9 @@ const doLoadFileContent = (e: MouseEvent) => {
102101
</a>
103102
<a
104103
v-else class="tree-item type-directory silenced"
105-
:class="{'selected': selectedItem === item.fullPath}"
104+
:class="{'selected': store.selectedItem === item.fullPath}"
106105
:title="item.entryName"
107-
:href="getWebUrl(item.fullPath)"
106+
:href="store.getWebUrl(item.fullPath)"
108107
@click.stop="doLoadDirContent"
109108
>
110109
<!-- directory -->
@@ -120,7 +119,7 @@ const doLoadFileContent = (e: MouseEvent) => {
120119
</a>
121120

122121
<div v-if="children?.length" v-show="!collapsed" class="sub-items">
123-
<ViewFileTreeItem v-for="childItem in children" :key="childItem.entryName" :item="childItem" :selected-item="selectedItem" :get-web-url="getWebUrl" :navigate-view-content="navigateViewContent" :load-children="loadChildren"/>
122+
<ViewFileTreeItem v-for="childItem in children" :key="childItem.entryName" :item="childItem" :store="store"/>
124123
</div>
125124
</template>
126125
<style scoped>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {reactive} from 'vue';
2+
import {GET} from '../modules/fetch.ts';
3+
import {pathEscapeSegments} from '../utils/url.ts';
4+
import {createElementFromHTML} from '../utils/dom.ts';
5+
6+
export function createViewFileTreeStore(props: { repoLink: string, treePath: string, currentRefNameSubURL: string}) {
7+
const store = reactive({
8+
rootFiles: [],
9+
selectedItem: props.treePath,
10+
11+
async loadChildren(treePath: string, subPath: string = '') {
12+
const response = await GET(`${props.repoLink}/tree-view/${props.currentRefNameSubURL}/${pathEscapeSegments(treePath)}?sub_path=${encodeURIComponent(subPath)}`);
13+
const json = await response.json();
14+
const poolSvgs = [];
15+
for (const [svgId, svgContent] of Object.entries(json.renderedIconPool ?? {})) {
16+
if (!document.querySelector(`.global-svg-icon-pool #${svgId}`)) poolSvgs.push(svgContent);
17+
}
18+
if (poolSvgs.length) {
19+
const svgContainer = createElementFromHTML('<div class="global-svg-icon-pool tw-hidden"></div>');
20+
svgContainer.innerHTML = poolSvgs.join('');
21+
document.body.append(svgContainer);
22+
}
23+
return json.fileTreeNodes ?? null;
24+
},
25+
26+
async loadViewContent(url: string) {
27+
url = url.includes('?') ? url.replace('?', '?only_content=true') : `${url}?only_content=true`;
28+
const response = await GET(url);
29+
document.querySelector('.repo-view-content').innerHTML = await response.text();
30+
},
31+
32+
async navigateTreeView(treePath: string) {
33+
const url = store.getWebUrl(treePath);
34+
window.history.pushState({treePath, url}, null, url);
35+
store.selectedItem = treePath;
36+
await store.loadViewContent(url);
37+
},
38+
39+
getWebUrl(treePath: string) {
40+
return `${props.repoLink}/src/${props.currentRefNameSubURL}/${pathEscapeSegments(treePath)}`;
41+
},
42+
});
43+
return store;
44+
}

0 commit comments

Comments
 (0)