如何使用库(jsTreeR)防止在叶节点上删除分支节点

How to prevent dropping branch nodes on leaf nodes with library(jsTreeR)

提问人:ahnungslos 提问时间:3/14/2023 更新时间:3/14/2023 访问量:42

问:

这是我之前在这里提出的问题的后续文章。

@StéphaneLaurent 和 @ismirsehregal 为我提供了一些关于如何自定义 jsTreeR 上下文菜单的很好的输入:

library(jsTreeR)
library(shiny)

nodes <- list(
  list(
    text = "Branch 1",
    state = list(opened = TRUE, disabled = FALSE),
    type = "parent",
    children = list(
      list(text = "Leaf A", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 1)),
      list(text = "Leaf B", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 2)),
      list(text = "Leaf C", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 3)),
      list(text = "Leaf D", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 4))
    )
  ),
  list(text = "Branch 2", type = "parent", state = list(opened = TRUE))
)

ui <- fluidPage(
  jstreeOutput("mytree")
)

customMenu <- JS(
  "function customMenu(node) {
  var tree = $('#mytree').jstree(true);
  var items = {
    'rename' : {
      'label' : 'Rename',
      'action' : function (obj) { tree.edit(node); },
      'icon': 'glyphicon glyphicon-edit'
    },
    'delete' : {
      'label' : 'Delete',
      'action' : function (obj) { tree.delete_node(node); },
      'icon' : 'glyphicon glyphicon-trash'
    },
    'create' : {
      'label' : 'Create',
      'action' : function (obj) { tree.create_node(node); },
      'icon': 'glyphicon glyphicon-plus'
    }
  }
  
  if (node.children.length > 0) { items.delete._disabled = true; }
  if (node.type === 'undeletable') { items.rename._disabled = true;
                                     items.delete._disabled = true;
                                     items.create._disabled = true;
                                    }

  return items;
}")

server <- function(input, output, session){
  output[["mytree"]] <- renderJstree({
    suppressMessages(jstree(
      nodes,
      search = list(
        show_only_matches = TRUE,
        case_sensitive = FALSE,
        search_leaves_only = FALSE
      ),
      dragAndDrop = TRUE,
      multiple = TRUE,
      contextMenu = list(items = customMenu),
      types = list(default = list(icon = "fa fa-caret-right"), undeletable = list(icon = "fa-solid fa-leaf"), parent = list(icon = "fa-brands fa-pagelines")),
      theme = "proton"
    ))
  })
}  

shinyApp(ui, server)

但是,最重要的是,我想防止在节点上丢弃分支节点

因此,我想区分不同的节点类型,而不是为整个树()配置它:dragAndDrop = TRUE

允许:

ok


不允许:

nok

JavaScript R 闪亮的 jstree jstreer

评论

0赞 Stéphane Laurent 3/14/2023
我认为这正是第一个例子。?jstree

答:

1赞 Stéphane Laurent 3/14/2023 #1

我认为你只需要:

dnd <- list(
  is_draggable = JS(
    "function(node) {",
    "  return node[0].type !== 'parent';",
    "}"
  )
)

jstree(
  nodes,
  dragAndDrop = TRUE, dnd = dnd,
  types = ......,
  checkCallback = TRUE
)

这样,分支节点就不可拖动了。这是你想要的吗?


编辑

关于您的评论:

checkCallback <- JS(
  "function(operation, node, parent, position, more) {",
  "  if(operation === 'move_node') {",
  "    if(parent.id === '#' || parent.type !== 'parent') {",
  "      return false;", # prevent moving a child above or below the root
  "    }",               # and moving inside a child
  "  }",
  "  return true;", # allow everything else
  "}"
)

jstree(
  nodes,
  dragAndDrop = TRUE, 
  types = ......,
  checkCallback = checkCallback
)

评论

0赞 ahnungslos 3/14/2023
谢谢!差不多就是这样了。现在我根本无法拖放分支。但是,我仍然希望能够通过拖放来嵌套树枝(我只是不想让树枝成为叶子的子项)。
0赞 ahnungslos 3/14/2023
if(parent.type === 'child'){return false;}按照我想要的方式工作。-谢谢!
0赞 Stéphane Laurent 3/14/2023
@ahnungslos 这是不可能的:你的代码中没有。type = "child"
0赞 Stéphane Laurent 3/14/2023
这就是我改用的原因。!== 'parent'
1赞 Stéphane Laurent 3/14/2023
@ahnungslos 这是因为我认为。parent.id === '#'