144 lines · 4.8 KB · Vue
RawDownload
<script>import DiffFileTreeItem from './DiffFileTreeItem.vue';import {loadMoreFiles} from '../features/repo-diff.js';import {toggleElem} from '../utils/dom.js';import {diffTreeStore} from '../modules/stores.js';import {setFileFolding} from '../features/file-fold.js'; const LOCAL_STORAGE_KEY = 'diff_file_tree_visible'; export default {  components: {DiffFileTreeItem},  data: () => {    return {store: diffTreeStore()};  },  computed: {    fileTree() {      const result = [];      for (const file of this.store.files) {        // Split file into directories        const splits = file.Name.split('/');        let index = 0;        let parent = null;        let isFile = false;        for (const split of splits) {          index += 1;          // reached the end          if (index === splits.length) {            isFile = true;          }          let newParent = {            name: split,            children: [],            isFile,          };           if (isFile === true) {            newParent.file = file;          }           if (parent) {            // check if the folder already exists            const existingFolder = parent.children.find(              (x) => x.name === split,            );            if (existingFolder) {              newParent = existingFolder;            } else {              parent.children.push(newParent);            }          } else {            const existingFolder = result.find((x) => x.name === split);            if (existingFolder) {              newParent = existingFolder;            } else {              result.push(newParent);            }          }          parent = newParent;        }      }      const mergeChildIfOnlyOneDir = (entries) => {        for (const entry of entries) {          if (entry.children) {            mergeChildIfOnlyOneDir(entry.children);          }          if (entry.children.length === 1 && entry.children[0].isFile === false) {            // Merge it to the parent            entry.name = `${entry.name}/${entry.children[0].name}`;            entry.children = entry.children[0].children;          }        }      };      // Merge folders with just a folder as children in order to      // reduce the depth of our tree.      mergeChildIfOnlyOneDir(result);      return result;    },  },  mounted() {    // Default to true if unset    this.store.fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) !== 'false';    document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', this.toggleVisibility);     this.hashChangeListener = () => {      this.store.selectedItem = window.location.hash;      this.expandSelectedFile();    };    this.hashChangeListener();    window.addEventListener('hashchange', this.hashChangeListener);  },  unmounted() {    document.querySelector('.diff-toggle-file-tree-button').removeEventListener('click', this.toggleVisibility);    window.removeEventListener('hashchange', this.hashChangeListener);  },  methods: {    expandSelectedFile() {      // expand file if the selected file is folded      if (this.store.selectedItem) {        const box = document.querySelector(this.store.selectedItem);        const folded = box?.getAttribute('data-folded') === 'true';        if (folded) setFileFolding(box, box.querySelector('.fold-file'), false);      }    },    toggleVisibility() {      this.updateVisibility(!this.store.fileTreeIsVisible);    },    updateVisibility(visible) {      this.store.fileTreeIsVisible = visible;      localStorage.setItem(LOCAL_STORAGE_KEY, this.store.fileTreeIsVisible);      this.updateState(this.store.fileTreeIsVisible);    },    updateState(visible) {      const btn = document.querySelector('.diff-toggle-file-tree-button');      const [toShow, toHide] = btn.querySelectorAll('.icon');      const tree = document.getElementById('diff-file-tree');      const newTooltip = btn.getAttribute(visible ? 'data-hide-text' : 'data-show-text');      btn.setAttribute('data-tooltip-content', newTooltip);      toggleElem(tree, visible);      toggleElem(toShow, !visible);      toggleElem(toHide, visible);    },    loadMoreData() {      loadMoreFiles(this.store.linkLoadMore);    },  },};</script><template>  <div v-if="store.fileTreeIsVisible" class="diff-file-tree-items">    <!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->    <DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item"/>    <div v-if="store.isIncomplete" class="tw-pt-1">      <a :class="['ui', 'basic', 'tiny', 'button', store.isLoadingNewData ? 'disabled' : '']" @click.stop="loadMoreData">{{ store.showMoreMessage }}</a>    </div>  </div></template><style scoped>.diff-file-tree-items {  display: flex;  flex-direction: column;  gap: 1px;  margin-right: .5rem;}</style>