fix: sidebar tree view (#764)

This commit is contained in:
Felix Häusler 2019-03-17 10:39:00 +01:00 committed by Ran Luo
parent 2007fc59e9
commit eff54dcaa1
6 changed files with 135 additions and 81 deletions

View File

@ -190,10 +190,7 @@ class AppWindow {
const unwatcher = this.watcher.watch(win, pathname)
this.windows.get(win.id).watchers.push(unwatcher)
try {
win.webContents.send('AGANI::open-project', {
name: path.basename(pathname),
pathname
})
win.webContents.send('AGANI::open-project', pathname)
} catch (err) {
log(err)
}

View File

@ -19,8 +19,10 @@
</template>
<script>
import path from 'path'
import { mapState } from 'vuex'
import { fileMixins } from '../../mixins'
import { PATH_SEPARATOR } from '../../config'
export default {
mixins: [fileMixins],
@ -36,14 +38,21 @@
tabs: state => state.editor.tabs,
currentFile: state => state.editor.currentFile
}),
// Return filename without extension.
filename () {
return this.file.name.split('.')[0]
return path.basename(this.file.name, path.extname(this.file.name))
},
// Return the filename extension or null.
extension () {
return `.${this.file.name.split('.')[1]}`
return path.extname(this.file.name)
},
// Return the parent directory with trailing path separator.
// NOTE: Parent from "Z:\" is "Z:\" on Windows!
parent () {
return this.file.pathname.match(/(?:^|\/)([^/]+)\/[^/]+\.[^/]+$/)[1] + '/'
return path.join(path.dirname(this.file.pathname), PATH_SEPARATOR)
}
}
}

View File

@ -82,6 +82,7 @@
import { remote } from 'electron'
import { mapState } from 'vuex'
import { minimizePath, restorePath, maximizePath, closePath } from '../assets/window-controls.js'
import { PATH_SEPARATOR } from '../config'
export default {
data () {
@ -134,7 +135,7 @@
}),
paths () {
if (!this.pathname) return []
const pathnameToken = this.pathname.split('/').filter(i => i)
const pathnameToken = this.pathname.split(PATH_SEPARATOR).filter(i => i)
return pathnameToken.slice(0, pathnameToken.length - 1).slice(-3)
}
},

View File

@ -1,3 +1,7 @@
import path from 'path'
export const PATH_SEPARATOR = path.sep
export const THEME_LINK_ID = 'ag-theme'
export const COMMON_STYLE_ID = 'ag-common-style'

View File

@ -3,6 +3,7 @@ import { ipcRenderer, shell } from 'electron'
import { addFile, unlinkFile, changeFile, addDirectory, unlinkDirectory } from './treeCtrl'
import bus from '../bus'
import { create, paste, rename } from '../util/fileSystem'
import { PATH_SEPARATOR } from '../config'
import notice from '../services/notification'
import { getFileStateFromData } from './help'
@ -36,9 +37,17 @@ const getters = {
}
const mutations = {
SET_PROJECT_TREE (state, { pathname, name }) {
SET_PROJECT_TREE (state, pathname) {
let name = path.basename(pathname)
if (!name) {
// Root directory such "/" or "C:\"
name = pathname
}
state.projectTree = {
pathname,
// Root full path
pathname: path.normalize(pathname),
// Root directory name
name,
isDirectory: true,
isFile: false,
@ -105,12 +114,12 @@ const mutations = {
const actions = {
LISTEN_FOR_LOAD_PROJECT ({ commit, dispatch }) {
ipcRenderer.on('AGANI::open-project', (e, { pathname, name }) => {
ipcRenderer.on('AGANI::open-project', (e, pathname) => {
// Initialize editor and show empty/new tab
dispatch('NEW_BLANK_FILE')
dispatch('INIT_STATUS', true)
commit('SET_PROJECT_TREE', { pathname, name })
commit('SET_PROJECT_TREE', pathname)
commit('SET_LAYOUT', {
rightColumn: 'files',
showSideBar: true,
@ -189,7 +198,7 @@ const actions = {
const { pathname, isDirectory } = state.activeItem
const dirname = isDirectory ? pathname : path.dirname(pathname)
if (clipboard) {
clipboard.dest = dirname + '/' + path.basename(clipboard.src)
clipboard.dest = dirname + PATH_SEPARATOR + path.basename(clipboard.src)
paste(clipboard)
.then(() => {
commit('SET_CLIPBOARD', null)
@ -232,7 +241,7 @@ const actions = {
RENAME_IN_SIDEBAR ({ commit, state }, name) {
const src = state.renameCache
const dirname = path.dirname(src)
const dest = dirname + '/' + name
const dest = dirname + PATH_SEPARATOR + name
rename(src, dest)
.then(() => {
commit('RENAME_IF_NEEDED', { src, dest })

View File

@ -1,34 +1,43 @@
import path from 'path'
import { getUniqueId } from '../util'
import { PATH_SEPARATOR } from '../config'
const pathSeparator = path.sep
const isWindows = process.platform === 'win32'
const getPathArr = (projectName, pathname) => {
const reUnix = /^\/+(.*)/
const reWindows = /^\\+(.*)/
let [prePath, partPath] = pathname.split(projectName)
partPath = partPath.replace(isWindows ? reWindows : reUnix, (_, p1) => p1)
prePath += projectName
const tokens = partPath ? partPath.split(pathSeparator) : []
return { prePath, tokens }
/**
* Return all sub-directories relative to the root directory.
*
* @param {string} rootPath Root directory path
* @param {string} pathname Full directory path
* @returns {Array<string>} Sub-directories relative to root.
*/
const getSubdirectoriesFromRoot = (rootPath, pathname) => {
if (!path.isAbsolute(pathname)) {
throw new Error('Invalid path!')
}
const relativePath = path.relative(rootPath, pathname)
return relativePath ? relativePath.split(PATH_SEPARATOR) : []
}
/**
* Add a new file to the tree list.
*
* @param {*} tree Root file tree
* @param {*} file The file that should be added
*/
export const addFile = (tree, file) => {
const { pathname, name } = file
const dirname = path.dirname(pathname)
let { prePath, tokens } = getPathArr(tree.name, dirname)
let folder = tree
let folders = tree.folders
const subDirectories = getSubdirectoriesFromRoot(tree.pathname, dirname)
for (const token of tokens) {
let childFolder = folders.find(f => f.name === token)
let currentPath = tree.pathname
let currentFolder = tree
let currentSubFolders = tree.folders
for (const directoryName of subDirectories) {
let childFolder = currentSubFolders.find(f => f.name === directoryName)
if (!childFolder) {
childFolder = {
id: getUniqueId(),
pathname: `${prePath}${pathSeparator}${token}`,
name: token,
pathname: `${currentPath}${PATH_SEPARATOR}${directoryName}`,
name: directoryName,
isCollapsed: true,
isDirectory: true,
isFile: false,
@ -36,30 +45,39 @@ export const addFile = (tree, file) => {
folders: [],
files: []
}
folders.push(childFolder)
currentSubFolders.push(childFolder)
}
prePath = `${prePath}${pathSeparator}${token}`
folder = childFolder
folders = childFolder.folders
currentPath = `${currentPath}${PATH_SEPARATOR}${directoryName}`
currentFolder = childFolder
currentSubFolders = childFolder.folders
}
if (!folder.files.find(f => f.name === name)) {
// Add file to related directory
if (!currentFolder.files.find(f => f.name === name)) {
file.id = getUniqueId()
folder.files.push(file)
currentFolder.files.push(file)
}
}
/**
* Add a new directory to the tree list.
*
* @param {*} tree Root file tree
* @param {*} dir The directory that should be added
*/
export const addDirectory = (tree, dir) => {
let { prePath, tokens } = getPathArr(tree.name, dir.pathname)
let folders = tree.folders
const subDirectories = getSubdirectoriesFromRoot(tree.pathname, dir.pathname)
for (const token of tokens) {
let childFolder = folders.find(f => f.name === token)
let currentPath = tree.pathname
let currentSubFolders = tree.folders
for (const directoryName of subDirectories) {
let childFolder = currentSubFolders.find(f => f.name === directoryName)
if (!childFolder) {
childFolder = {
id: getUniqueId(),
pathname: `${prePath}${pathSeparator}${token}`,
name: token,
pathname: `${currentPath}${PATH_SEPARATOR}${directoryName}`,
name: directoryName,
isCollapsed: true,
isDirectory: true,
isFile: false,
@ -67,70 +85,86 @@ export const addDirectory = (tree, dir) => {
folders: [],
files: []
}
folders.push(childFolder)
currentSubFolders.push(childFolder)
}
prePath = `${prePath}${pathSeparator}${token}`
folders = childFolder.folders
currentPath = `${currentPath}${PATH_SEPARATOR}${directoryName}`
currentSubFolders = childFolder.folders
}
}
/**
* Remove the given file from the tree list.
*
* @param {*} tree Root file tree
* @param {*} file The file that should be deleted
*/
export const unlinkFile = (tree, file) => {
const { pathname } = file
const dirname = path.dirname(pathname)
let { tokens } = getPathArr(tree.name, dirname)
const subDirectories = getSubdirectoriesFromRoot(tree.pathname, dirname)
let folder = tree
let folders = tree.folders
for (const token of tokens) {
const childFolder = folders.find(f => f.name === token)
let currentFolder = tree
let currentSubFolders = tree.folders
for (const directoryName of subDirectories) {
const childFolder = currentSubFolders.find(f => f.name === directoryName)
if (!childFolder) return
folder = childFolder
folders = childFolder.folders
currentFolder = childFolder
currentSubFolders = childFolder.folders
}
const index = folder.files.findIndex(f => f.pathname === pathname)
if (index > -1) {
folder.files.splice(index, 1)
const index = currentFolder.files.findIndex(f => f.pathname === pathname)
if (index !== -1) {
currentFolder.files.splice(index, 1)
}
}
/**
* Update a given file in the tree list.
*
* @param {*} tree Root file tree
* @param {*} file The file that was changed
*/
export const changeFile = (tree, file) => {
const { pathname, data } = file
const dirname = path.dirname(pathname)
let { tokens } = getPathArr(tree.name, dirname)
const subDirectories = getSubdirectoriesFromRoot(tree.pathname, dirname)
let folder = tree
let folders = tree.folders
for (const token of tokens) {
const childFolder = folders.find(f => f.name === token)
let currentFolder = tree
let currentSubFolders = tree.folders
for (const directoryName of subDirectories) {
const childFolder = currentSubFolders.find(f => f.name === directoryName)
if (!childFolder) return
folder = childFolder
folders = childFolder.folders
currentFolder = childFolder
currentSubFolders = childFolder.folders
}
const index = folder.files.findIndex(f => f.pathname === pathname)
folder.files[index].data = data
const index = currentFolder.files.findIndex(f => f.pathname === pathname)
if (index !== -1) {
currentFolder.files[index].data = data
}
}
/**
* Remove the given directory from the tree list.
*
* @param {*} tree Root file tree
* @param {*} dir The directory that should be deleted
*/
export const unlinkDirectory = (tree, dir) => {
const { pathname } = dir
const { tokens } = getPathArr(tree.name, pathname)
const subDirectories = getSubdirectoriesFromRoot(tree.pathname, pathname)
tokens.pop()
let folders = tree.folders
for (const token of tokens) {
const childFolder = folders.find(f => f.name === token)
subDirectories.pop()
let currentFolder = tree.folders
for (const directoryName of subDirectories) {
const childFolder = currentFolder.find(f => f.name === directoryName)
if (!childFolder) return
folders = childFolder.folders
currentFolder = childFolder.folders
}
const index = folders.findIndex(f => f.pathname === pathname)
if (index > -1) {
folders.splice(index, 1)
const index = currentFolder.findIndex(f => f.pathname === pathname)
if (index !== -1) {
currentFolder.splice(index, 1)
}
}