🎨 文档树支持 Ctrl+ClickShift+↑/↓ 进行多选 https://github.com/siyuan-note/siyuan/issues/1359

This commit is contained in:
Liang Ding 2022-11-03 14:27:17 +08:00
parent c8680c9fb3
commit e45a0694bd
No known key found for this signature in database
GPG key ID: 136F30F901A2231D
4 changed files with 168 additions and 26 deletions

View file

@ -267,6 +267,31 @@ func moveDoc(c *gin.Context) {
util.PushEvent(evt)
}
func moveDocs(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
arg, ok := util.JsonArg(c, ret)
if !ok {
return
}
var fromPaths []string
fromPathsArg := arg["fromPaths"].([]interface{})
for _, fromPath := range fromPathsArg {
fromPaths = append(fromPaths, fromPath.(string))
}
toPath := arg["toPath"].(string)
err := model.MoveDocs(fromPaths, toPath)
if nil != err {
ret.Code = -1
ret.Msg = err.Error()
ret.Data = map[string]interface{}{"closeTimeout": 7000}
return
}
}
func removeDoc(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
@ -294,6 +319,28 @@ func removeDoc(c *gin.Context) {
util.PushEvent(evt)
}
func removeDocs(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
arg, ok := util.JsonArg(c, ret)
if !ok {
return
}
pathsArg := arg["paths"].([]interface{})
var paths []string
for _, path := range pathsArg {
paths = append(paths, path.(string))
}
err := model.RemoveDocs(paths)
if nil != err {
ret.Code = -1
ret.Msg = err.Error()
return
}
}
func renameDoc(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)

View file

@ -87,7 +87,9 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/filetree/createDoc", model.CheckAuth, model.CheckReadonly, createDoc)
ginServer.Handle("POST", "/api/filetree/renameDoc", model.CheckAuth, model.CheckReadonly, renameDoc)
ginServer.Handle("POST", "/api/filetree/removeDoc", model.CheckAuth, model.CheckReadonly, removeDoc)
ginServer.Handle("POST", "/api/filetree/removeDocs", model.CheckAuth, model.CheckReadonly, removeDocs)
ginServer.Handle("POST", "/api/filetree/moveDoc", model.CheckAuth, model.CheckReadonly, moveDoc)
ginServer.Handle("POST", "/api/filetree/moveDocs", model.CheckAuth, model.CheckReadonly, moveDocs)
ginServer.Handle("POST", "/api/filetree/duplicateDoc", model.CheckAuth, model.CheckReadonly, duplicateDoc)
ginServer.Handle("POST", "/api/filetree/getHPathByPath", model.CheckAuth, getHPathByPath)
ginServer.Handle("POST", "/api/filetree/getHPathByID", model.CheckAuth, getHPathByID)

View file

@ -545,3 +545,14 @@ func TryAccessFileByBlockID(id string) (ok bool) {
}
return true
}
func getBoxesByPaths(paths []string) (ret map[string]*Box) {
for _, p := range paths {
id := strings.TrimSuffix(path.Base(p), ".sy")
bt := treenode.GetBlockTree(id)
if nil != bt {
ret[p] = Conf.Box(bt.BoxID)
}
}
return
}

View file

@ -988,6 +988,8 @@ func GetFullHPathByID(id string) (hPath string, err error) {
}
func MoveDoc(fromBoxID, fromPath, toBoxID, toPath string) (newPath string, err error) {
WaitForWritingFiles()
if fromBoxID == toBoxID && fromPath == toPath {
return
}
@ -1004,13 +1006,6 @@ func MoveDoc(fromBoxID, fromPath, toBoxID, toPath string) (newPath string, err e
return
}
WaitForWritingFiles()
tree, err := LoadTree(fromBoxID, fromPath)
if nil != err {
err = ErrBlockNotFound
return
}
childDepth := util.GetChildDocDepth(filepath.Join(util.DataDir, fromBoxID, fromPath))
if depth := strings.Count(toPath, "/") + childDepth; 6 < depth && !Conf.FileTree.AllowCreateDeeper {
err = errors.New(Conf.Language(118))
@ -1022,7 +1017,19 @@ func MoveDoc(fromBoxID, fromPath, toBoxID, toPath string) (newPath string, err e
err = errors.New(Conf.Language(0))
return
}
isSameBox := fromBoxID == toBoxID
newPath, err = moveDoc(fromBox, fromPath, toBox, toPath)
if nil != err {
return
}
cache.ClearDocsIAL()
IncSync()
return
}
func moveDoc(fromBox *Box, fromPath string, toBox *Box, toPath string) (newPath string, err error) {
isSameBox := fromBox.ID == toBox.ID
if isSameBox {
if !fromBox.Exist(toPath) {
@ -1036,6 +1043,12 @@ func MoveDoc(fromBoxID, fromPath, toBoxID, toPath string) (newPath string, err e
}
}
tree, err := LoadTree(fromBox.ID, fromPath)
if nil != err {
err = ErrBlockNotFound
return
}
moveToRoot := "/" == toPath
toBlockID := tree.ID
fromFolder := path.Join(path.Dir(fromPath), tree.ID)
@ -1043,9 +1056,9 @@ func MoveDoc(fromBoxID, fromPath, toBoxID, toPath string) (newPath string, err e
if !moveToRoot {
var toTree *parse.Tree
if isSameBox {
toTree, err = LoadTree(fromBoxID, toPath)
toTree, err = LoadTree(fromBox.ID, toPath)
} else {
toTree, err = LoadTree(toBoxID, toPath)
toTree, err = LoadTree(toBox.ID, toPath)
}
if nil != err {
err = ErrBlockNotFound
@ -1075,14 +1088,14 @@ func MoveDoc(fromBoxID, fromPath, toBoxID, toPath string) (newPath string, err e
return
}
} else {
absFromPath := filepath.Join(util.DataDir, fromBoxID, fromFolder)
absToPath := filepath.Join(util.DataDir, toBoxID, newFolder)
absFromPath := filepath.Join(util.DataDir, fromBox.ID, fromFolder)
absToPath := filepath.Join(util.DataDir, toBox.ID, newFolder)
if gulu.File.IsExist(absToPath) {
filelock.Remove(absToPath)
}
if err = filelock.Move(absFromPath, absToPath); nil != err {
msg := fmt.Sprintf(Conf.Language(5), fromBox.Name, fromPath, err)
logging.LogErrorf("move [path=%s] in box [%s] failed: %s", fromPath, fromBoxID, err)
logging.LogErrorf("move [path=%s] in box [%s] failed: %s", fromPath, fromBox.ID, err)
err = errors.New(msg)
return
}
@ -1096,32 +1109,68 @@ func MoveDoc(fromBoxID, fromPath, toBoxID, toPath string) (newPath string, err e
return
}
tree, err = LoadTree(fromBoxID, newPath)
tree, err = LoadTree(fromBox.ID, newPath)
if nil != err {
return
}
moveTree(tree)
} else {
absFromPath := filepath.Join(util.DataDir, fromBoxID, fromPath)
absToPath := filepath.Join(util.DataDir, toBoxID, newPath)
absFromPath := filepath.Join(util.DataDir, fromBox.ID, fromPath)
absToPath := filepath.Join(util.DataDir, toBox.ID, newPath)
if err = filelock.Move(absFromPath, absToPath); nil != err {
msg := fmt.Sprintf(Conf.Language(5), fromBox.Name, fromPath, err)
logging.LogErrorf("move [path=%s] in box [%s] failed: %s", fromPath, fromBoxID, err)
logging.LogErrorf("move [path=%s] in box [%s] failed: %s", fromPath, fromBox.ID, err)
err = errors.New(msg)
return
}
tree, err = LoadTree(toBoxID, newPath)
tree, err = LoadTree(toBox.ID, newPath)
if nil != err {
return
}
moveTree(tree)
moveSorts(tree.ID, fromBoxID, toBoxID)
moveSorts(tree.ID, fromBox.ID, toBox.ID)
}
return
}
func MoveDocs(fromPaths []string, toPath string) (err error) {
util.PushEndlessProgress(Conf.Language(116))
util.PushEndlessProgress(Conf.Language(113))
sql.WaitForWritingDatabase()
util.ReloadUI()
return
}
func filterFromPaths(fromPaths []string, toPath string) (retFromPaths []string) {
fromPaths = append(fromPaths, toPath)
retFromPaths = filterSelfChildDocs(fromPaths)
return
}
func filterSelfChildDocs(paths []string) (ret []string) {
sort.Slice(paths, func(i, j int) bool { return len(paths[i]) < len(paths[j]) })
dirs := map[string]string{}
for _, fromPath := range paths {
dir := strings.TrimSuffix(fromPath, ".sy")
existParent := false
for _, d := range dirs {
if strings.HasPrefix(d, fromPath) {
existParent = true
break
}
}
if existParent {
continue
}
dirs[dir] = fromPath
ret = append(ret, fromPath)
}
cache.ClearDocsIAL()
IncSync()
return
}
@ -1133,7 +1182,40 @@ func RemoveDoc(boxID, p string) (err error) {
}
WaitForWritingFiles()
tree, err := LoadTree(boxID, p)
err = removeDoc(box, p)
if nil != err {
return
}
IncSync()
return
}
func RemoveDocs(paths []string) (err error) {
util.PushEndlessProgress(Conf.Language(116))
paths = filterSelfChildDocs(paths)
var ids []string
for _, p := range paths {
ids = append(ids, strings.TrimSuffix(path.Base(p), ".sy"))
}
boxes := getBoxesByPaths(ids)
WaitForWritingFiles()
for p, box := range boxes {
err = removeDoc(box, p)
if nil != err {
return
}
}
util.PushEndlessProgress(Conf.Language(113))
sql.WaitForWritingDatabase()
util.ReloadUI()
return
}
func removeDoc(box *Box, p string) (err error) {
tree, err := LoadTree(box.ID, p)
if nil != err {
return
}
@ -1144,13 +1226,13 @@ func RemoveDoc(boxID, p string) (err error) {
return
}
historyPath := filepath.Join(historyDir, boxID, p)
absPath := filepath.Join(util.DataDir, boxID, p)
historyPath := filepath.Join(historyDir, box.ID, p)
absPath := filepath.Join(util.DataDir, box.ID, p)
if err = filelock.Copy(absPath, historyPath); nil != err {
return errors.New(fmt.Sprintf(Conf.Language(70), box.Name, absPath, err))
}
copyDocAssetsToDataAssets(boxID, p)
copyDocAssetsToDataAssets(box.ID, p)
rootID := tree.ID
dir := path.Dir(p)
@ -1178,7 +1260,7 @@ func RemoveDoc(boxID, p string) (err error) {
sql.RemoveTreePathQueue(box.ID, childrenDir)
if "/" != dir {
others, err := os.ReadDir(filepath.Join(util.DataDir, boxID, dir))
others, err := os.ReadDir(filepath.Join(util.DataDir, box.ID, dir))
if nil == err && 1 > len(others) {
box.Remove(dir)
}