marktext/src/renderer/store/project.js
2023-08-08 22:45:42 +08:00

232 lines
6.4 KiB
JavaScript

import path from 'path'
import { ipcRenderer, shell } from 'electron'
import { addFile, unlinkFile, 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'
import { hasMarkdownExtension } from '../../common/filesystem/paths'
const state = {
activeItem: {},
createCache: {},
// Use to cache newly created filename, for open immediately.
newFileNameCache: '',
renameCache: null,
clipboard: null,
projectTree: null
}
const getters = {}
const mutations = {
SET_ROOT_DIRECTORY (state, pathname) {
let name = path.basename(pathname)
if (!name) {
// Root directory such "/" or "C:\"
name = pathname
}
state.projectTree = {
// Root full path
pathname: path.normalize(pathname),
// Root directory name
name,
isDirectory: true,
isFile: false,
isMarkdown: false,
folders: [],
files: []
}
},
SET_NEWFILENAME (state, name) {
state.newFileNameCache = name
},
ADD_FILE (state, change) {
const { projectTree } = state
addFile(projectTree, change)
},
UNLINK_FILE (state, change) {
const { projectTree } = state
unlinkFile(projectTree, change)
},
ADD_DIRECTORY (state, change) {
const { projectTree } = state
addDirectory(projectTree, change)
},
UNLINK_DIRECTORY (state, change) {
const { projectTree } = state
unlinkDirectory(projectTree, change)
},
SET_ACTIVE_ITEM (state, activeItem) {
state.activeItem = activeItem
},
SET_CLIPBOARD (state, data) {
state.clipboard = data
},
CREATE_PATH (state, cache) {
state.createCache = cache
},
SET_RENAME_CACHE (state, cache) {
state.renameCache = cache
}
}
const actions = {
LISTEN_FOR_LOAD_PROJECT ({ commit, dispatch }) {
ipcRenderer.on('mt::open-directory', (e, pathname) => {
commit('SET_ROOT_DIRECTORY', pathname)
commit('SET_LAYOUT', {
rightColumn: 'files',
showSideBar: true,
showTabBar: true
})
dispatch('DISPATCH_LAYOUT_MENU_ITEMS')
})
},
LISTEN_FOR_UPDATE_PROJECT ({ commit, state, dispatch }) {
ipcRenderer.on('mt::update-object-tree', (e, { type, change }) => {
switch (type) {
case 'add': {
const { pathname, data, isMarkdown } = change
commit('ADD_FILE', change)
if (isMarkdown && state.newFileNameCache && pathname === state.newFileNameCache) {
const fileState = getFileStateFromData(data)
dispatch('UPDATE_CURRENT_FILE', fileState)
commit('SET_NEWFILENAME', '')
}
break
}
case 'unlink':
commit('UNLINK_FILE', change)
commit('SET_SAVE_STATUS_WHEN_REMOVE', change)
break
case 'addDir':
commit('ADD_DIRECTORY', change)
break
case 'unlinkDir':
commit('UNLINK_DIRECTORY', change)
break
case 'change':
break
default:
if (process.env.NODE_ENV === 'development') {
console.log(`Unknown directory watch type: "${type}"`)
}
break
}
})
},
CHANGE_ACTIVE_ITEM ({ commit }, activeItem) {
commit('SET_ACTIVE_ITEM', activeItem)
},
CHANGE_CLIPBOARD ({ commit }, data) {
commit('SET_CLIPBOARD', data)
},
ASK_FOR_OPEN_PROJECT ({ commit }) {
ipcRenderer.send('mt::ask-for-open-project-in-sidebar')
},
LISTEN_FOR_SIDEBAR_CONTEXT_MENU ({ commit, state }) {
bus.$on('SIDEBAR::show-in-folder', () => {
const { pathname } = state.activeItem
shell.showItemInFolder(pathname)
})
bus.$on('SIDEBAR::new', type => {
const { pathname, isDirectory } = state.activeItem
const dirname = isDirectory ? pathname : path.dirname(pathname)
commit('CREATE_PATH', { dirname, type })
bus.$emit('SIDEBAR::show-new-input')
})
bus.$on('SIDEBAR::remove', () => {
const { pathname } = state.activeItem
ipcRenderer.invoke('mt::fs-trash-item', pathname).catch(err => {
notice.notify({
title: 'Error while deleting',
type: 'error',
message: err.message
})
})
})
bus.$on('SIDEBAR::copy-cut', type => {
const { pathname: src } = state.activeItem
commit('SET_CLIPBOARD', { type, src })
})
bus.$on('SIDEBAR::paste', () => {
const { clipboard } = state
const { pathname, isDirectory } = state.activeItem
const dirname = isDirectory ? pathname : path.dirname(pathname)
if (clipboard && clipboard.src) {
clipboard.dest = dirname + PATH_SEPARATOR + path.basename(clipboard.src)
if (path.normalize(clipboard.src) === path.normalize(clipboard.dest)) {
notice.notify({
title: 'Paste Forbidden',
type: 'warning',
message: 'Source and destination must not be the same.'
})
return
}
paste(clipboard)
.then(() => {
commit('SET_CLIPBOARD', null)
})
.catch(err => {
notice.notify({
title: 'Error while pasting',
type: 'error',
message: err.message
})
})
}
})
bus.$on('SIDEBAR::rename', () => {
const { pathname } = state.activeItem
commit('SET_RENAME_CACHE', pathname)
bus.$emit('SIDEBAR::show-rename-input')
})
},
CREATE_FILE_DIRECTORY ({ commit, state }, name) {
const { dirname, type } = state.createCache
if (type === 'file' && !hasMarkdownExtension(name)) {
name += '.md'
}
const fullName = `${dirname}/${name}`
create(fullName, type)
.then(() => {
commit('CREATE_PATH', {})
if (type === 'file') {
commit('SET_NEWFILENAME', fullName)
}
})
.catch(err => {
notice.notify({
title: 'Error in Side Bar',
type: 'error',
message: err.message
})
})
},
RENAME_IN_SIDEBAR ({ commit, state }, name) {
const src = state.renameCache
const dirname = path.dirname(src)
const dest = dirname + PATH_SEPARATOR + name
rename(src, dest)
.then(() => {
commit('RENAME_IF_NEEDED', { src, dest })
})
},
OPEN_SETTING_WINDOW () {
ipcRenderer.send('mt::open-setting-window')
}
}
export default { state, getters, mutations, actions }