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) const unwatcher = this.watcher.watch(win, pathname)
this.windows.get(win.id).watchers.push(unwatcher) this.windows.get(win.id).watchers.push(unwatcher)
try { try {
win.webContents.send('AGANI::open-project', { win.webContents.send('AGANI::open-project', pathname)
name: path.basename(pathname),
pathname
})
} catch (err) { } catch (err) {
log(err) log(err)
} }

View File

@ -19,8 +19,10 @@
</template> </template>
<script> <script>
import path from 'path'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { fileMixins } from '../../mixins' import { fileMixins } from '../../mixins'
import { PATH_SEPARATOR } from '../../config'
export default { export default {
mixins: [fileMixins], mixins: [fileMixins],
@ -36,14 +38,21 @@
tabs: state => state.editor.tabs, tabs: state => state.editor.tabs,
currentFile: state => state.editor.currentFile currentFile: state => state.editor.currentFile
}), }),
// Return filename without extension.
filename () { 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 () { 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 () { 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 { remote } from 'electron'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { minimizePath, restorePath, maximizePath, closePath } from '../assets/window-controls.js' import { minimizePath, restorePath, maximizePath, closePath } from '../assets/window-controls.js'
import { PATH_SEPARATOR } from '../config'
export default { export default {
data () { data () {
@ -134,7 +135,7 @@
}), }),
paths () { paths () {
if (!this.pathname) return [] 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) 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 THEME_LINK_ID = 'ag-theme'
export const COMMON_STYLE_ID = 'ag-common-style' 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 { addFile, unlinkFile, changeFile, addDirectory, unlinkDirectory } from './treeCtrl'
import bus from '../bus' import bus from '../bus'
import { create, paste, rename } from '../util/fileSystem' import { create, paste, rename } from '../util/fileSystem'
import { PATH_SEPARATOR } from '../config'
import notice from '../services/notification' import notice from '../services/notification'
import { getFileStateFromData } from './help' import { getFileStateFromData } from './help'
@ -36,9 +37,17 @@ const getters = {
} }
const mutations = { 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 = { state.projectTree = {
pathname, // Root full path
pathname: path.normalize(pathname),
// Root directory name
name, name,
isDirectory: true, isDirectory: true,
isFile: false, isFile: false,
@ -105,12 +114,12 @@ const mutations = {
const actions = { const actions = {
LISTEN_FOR_LOAD_PROJECT ({ commit, dispatch }) { 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 // Initialize editor and show empty/new tab
dispatch('NEW_BLANK_FILE') dispatch('NEW_BLANK_FILE')
dispatch('INIT_STATUS', true) dispatch('INIT_STATUS', true)
commit('SET_PROJECT_TREE', { pathname, name }) commit('SET_PROJECT_TREE', pathname)
commit('SET_LAYOUT', { commit('SET_LAYOUT', {
rightColumn: 'files', rightColumn: 'files',
showSideBar: true, showSideBar: true,
@ -189,7 +198,7 @@ const actions = {
const { pathname, isDirectory } = state.activeItem const { pathname, isDirectory } = state.activeItem
const dirname = isDirectory ? pathname : path.dirname(pathname) const dirname = isDirectory ? pathname : path.dirname(pathname)
if (clipboard) { if (clipboard) {
clipboard.dest = dirname + '/' + path.basename(clipboard.src) clipboard.dest = dirname + PATH_SEPARATOR + path.basename(clipboard.src)
paste(clipboard) paste(clipboard)
.then(() => { .then(() => {
commit('SET_CLIPBOARD', null) commit('SET_CLIPBOARD', null)
@ -232,7 +241,7 @@ const actions = {
RENAME_IN_SIDEBAR ({ commit, state }, name) { RENAME_IN_SIDEBAR ({ commit, state }, name) {
const src = state.renameCache const src = state.renameCache
const dirname = path.dirname(src) const dirname = path.dirname(src)
const dest = dirname + '/' + name const dest = dirname + PATH_SEPARATOR + name
rename(src, dest) rename(src, dest)
.then(() => { .then(() => {
commit('RENAME_IF_NEEDED', { src, dest }) commit('RENAME_IF_NEEDED', { src, dest })

View File

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