Fancytree 选择模式 3 和拖放挑战
Fancytree selectmode 3 and drag and drop challenges
我更喜欢使用 Fancytree 的 select 模式 3,因为我相信这会为用户带来最直观的体验(其中 selecting 一个 parent 节点自动 selects children)。但是,我注意到当我使用带有 dnd5 扩展名的模式时,拖放文件夹时文件夹的层次结构会丢失(有一个例外)。
我已经设置了一个 codepen 来演示这个问题。如果您 select 文件夹 4 旁边的复选框并将其拖到文件夹 3,当您放下它时,所有层次结构都会丢失。当使用select模式2时,情况就不是这样了。有趣的是,如果您不选中该框,而只是抓住文件夹 4 并移动它,层次结构仍然存在。
我查看了调试和控制台(特别是 data.otherNodeList),我观察到当(在 select 模式 3 中)如果我选中复选框,parent 文件夹节点和 children 节点都被视为单独的叶节点,事实上,如果您检查文件夹节点,它会说它没有 children。但是,如果(仍处于 select 模式 3)我只是在不选中复选框的情况下获取文件夹,则 child 节点嵌套在文件夹下方,并且文件夹指示它具有 children.
就是说,有没有人知道在移动的文件夹中维护层次结构的变通方法?我真的更喜欢使用 select 模式 3,因为它在我的代码的其他区域用于下载和删除。另外,我觉得它更 auto-selection 是最终用户所期望的。
$("#tree").fancytree({
checkbox: true,
selectMode: 3,
extensions: ["dnd5", "multi"],
debugLevel: 0,
source: [
// Typically we would load using ajax instead...
{ title: "Node 1" },
{ title: "Node 2" },
{
title: "Folder 3",
folder: true,
expanded: true,
children: [
{ title: "Node 3.1", key: "id3.1" },
{ title: "Node 3.2" }
]
},
{
title: "Folder 4",
folder: true,
expanded: true,
children: [{ title: "Node 4.1" }, { title: "Node 4.2" }]
}
],
activate: function(event, data) {
$("#statusLine").text(event.type + ": " + data.node);
},
select: function(event, data) {
$("#statusLine").text(
event.type + ": " + data.node.isSelected() + " " + data.node
);
},
dnd5: {
preventVoidMoves: true, // Prevent moving nodes 'before self', etc.
preventRecursion: true, // Prevent dropping nodes on own descendants
preventSameParent: false, // Prevent dropping nodes under the same direct parent
autoExpandMS: 1000,
multiSource: true, // drag all selected nodes (plus current node)
// focusOnClick: true,
// refreshPositions: true,
dragStart: function(node, data) {
// allow dragging `node`:
data.effectAllowed = "all";
data.dropEffect = data.dropEffectSuggested; //"link";
// data.dropEffect = "move";
return true;
},
// dragDrag: function(node, data) {
// data.node.info("dragDrag", data);
// data.dropEffect = "copy";
// return true;
// },
dragEnter: function(node, data) {
data.node.info("dragEnter", data);
// data.dropEffect = "link";
return true;
},
dragOver: function(node, data) {
// data.node.info("dragOver", data);
data.dropEffect = data.dropEffectSuggested; //"link";
return true;
},
dragEnd: function(node, data) {
data.node.info("dragEnd", data);
},
dragDrop: function(node, data) {
// This function MUST be defined to enable dropping of items on the tree.
//
// The source data is provided in several formats:
// `data.otherNode` (null if it's not a FancytreeNode from the same page)
// `data.otherNodeData` (Json object; null if it's not a FancytreeNode)
// `data.dataTransfer.getData()`
//
// We may access some meta data to decide what to do:
// `data.hitMode` ("before", "after", or "over").
// `data.dropEffect`, `.effectAllowed`
// `data.originalEvent.shiftKey`, ...
//
// Example:
var sourceNodes = data.otherNodeList,
copyMode = data.dropEffect !== "move";
console.log("sourceNodes below");
console.log(sourceNodes);
if( data.hitMode === "after" ){
// If node are inserted directly after tagrget node one-by-one,
// this would reverse them. So we compensate:
sourceNodes.reverse();
}
if( copyMode ) {
$.each(sourceNodes, function(i, o){
o.info("copy to " + node + ": " + data.hitMode);
o.copyTo(node, data.hitMode, function(n){
delete n.key;
n.selected = false;
n.title = "Copy of " + n.title;
});
});
} else {
$.each(sourceNodes, function(i, o){
o.info("move to " + node + ": " + data.hitMode);
o.moveTo(node, data.hitMode);
});
}
node.debug("drop", data);
node.setExpanded();
}
}
});
此代码将所有选定 个节点移动为目标节点的子节点:
var sourceNodes = data.otherNodeList;
...
$.each(sourceNodes, function(i, o){
o.info("move to " + node + ": " + data.hitMode);
o.moveTo(node, data.hitMode);
});
我想在你的情况下你只想移动拖动源,它是顶部节点 otherNode
:
data.otherNode.moveTo(node, data.hitMode);
如果您需要移动超过一个顶级节点,另一种选择是实施 dnd5. multiSource
回调和 return 仅包含这些节点的修改列表。
对于那些可能正在寻找类似东西的人,这是我使用的回调。
multiSource: function(node, data) {
var topMostSelected = data.tree.getSelectedNodes(true);
return topMostSelected;
}
我更喜欢使用 Fancytree 的 select 模式 3,因为我相信这会为用户带来最直观的体验(其中 selecting 一个 parent 节点自动 selects children)。但是,我注意到当我使用带有 dnd5 扩展名的模式时,拖放文件夹时文件夹的层次结构会丢失(有一个例外)。
我已经设置了一个 codepen 来演示这个问题。如果您 select 文件夹 4 旁边的复选框并将其拖到文件夹 3,当您放下它时,所有层次结构都会丢失。当使用select模式2时,情况就不是这样了。有趣的是,如果您不选中该框,而只是抓住文件夹 4 并移动它,层次结构仍然存在。
我查看了调试和控制台(特别是 data.otherNodeList),我观察到当(在 select 模式 3 中)如果我选中复选框,parent 文件夹节点和 children 节点都被视为单独的叶节点,事实上,如果您检查文件夹节点,它会说它没有 children。但是,如果(仍处于 select 模式 3)我只是在不选中复选框的情况下获取文件夹,则 child 节点嵌套在文件夹下方,并且文件夹指示它具有 children.
就是说,有没有人知道在移动的文件夹中维护层次结构的变通方法?我真的更喜欢使用 select 模式 3,因为它在我的代码的其他区域用于下载和删除。另外,我觉得它更 auto-selection 是最终用户所期望的。
$("#tree").fancytree({
checkbox: true,
selectMode: 3,
extensions: ["dnd5", "multi"],
debugLevel: 0,
source: [
// Typically we would load using ajax instead...
{ title: "Node 1" },
{ title: "Node 2" },
{
title: "Folder 3",
folder: true,
expanded: true,
children: [
{ title: "Node 3.1", key: "id3.1" },
{ title: "Node 3.2" }
]
},
{
title: "Folder 4",
folder: true,
expanded: true,
children: [{ title: "Node 4.1" }, { title: "Node 4.2" }]
}
],
activate: function(event, data) {
$("#statusLine").text(event.type + ": " + data.node);
},
select: function(event, data) {
$("#statusLine").text(
event.type + ": " + data.node.isSelected() + " " + data.node
);
},
dnd5: {
preventVoidMoves: true, // Prevent moving nodes 'before self', etc.
preventRecursion: true, // Prevent dropping nodes on own descendants
preventSameParent: false, // Prevent dropping nodes under the same direct parent
autoExpandMS: 1000,
multiSource: true, // drag all selected nodes (plus current node)
// focusOnClick: true,
// refreshPositions: true,
dragStart: function(node, data) {
// allow dragging `node`:
data.effectAllowed = "all";
data.dropEffect = data.dropEffectSuggested; //"link";
// data.dropEffect = "move";
return true;
},
// dragDrag: function(node, data) {
// data.node.info("dragDrag", data);
// data.dropEffect = "copy";
// return true;
// },
dragEnter: function(node, data) {
data.node.info("dragEnter", data);
// data.dropEffect = "link";
return true;
},
dragOver: function(node, data) {
// data.node.info("dragOver", data);
data.dropEffect = data.dropEffectSuggested; //"link";
return true;
},
dragEnd: function(node, data) {
data.node.info("dragEnd", data);
},
dragDrop: function(node, data) {
// This function MUST be defined to enable dropping of items on the tree.
//
// The source data is provided in several formats:
// `data.otherNode` (null if it's not a FancytreeNode from the same page)
// `data.otherNodeData` (Json object; null if it's not a FancytreeNode)
// `data.dataTransfer.getData()`
//
// We may access some meta data to decide what to do:
// `data.hitMode` ("before", "after", or "over").
// `data.dropEffect`, `.effectAllowed`
// `data.originalEvent.shiftKey`, ...
//
// Example:
var sourceNodes = data.otherNodeList,
copyMode = data.dropEffect !== "move";
console.log("sourceNodes below");
console.log(sourceNodes);
if( data.hitMode === "after" ){
// If node are inserted directly after tagrget node one-by-one,
// this would reverse them. So we compensate:
sourceNodes.reverse();
}
if( copyMode ) {
$.each(sourceNodes, function(i, o){
o.info("copy to " + node + ": " + data.hitMode);
o.copyTo(node, data.hitMode, function(n){
delete n.key;
n.selected = false;
n.title = "Copy of " + n.title;
});
});
} else {
$.each(sourceNodes, function(i, o){
o.info("move to " + node + ": " + data.hitMode);
o.moveTo(node, data.hitMode);
});
}
node.debug("drop", data);
node.setExpanded();
}
}
});
此代码将所有选定 个节点移动为目标节点的子节点:
var sourceNodes = data.otherNodeList;
...
$.each(sourceNodes, function(i, o){
o.info("move to " + node + ": " + data.hitMode);
o.moveTo(node, data.hitMode);
});
我想在你的情况下你只想移动拖动源,它是顶部节点 otherNode
:
data.otherNode.moveTo(node, data.hitMode);
如果您需要移动超过一个顶级节点,另一种选择是实施 dnd5. multiSource
回调和 return 仅包含这些节点的修改列表。
对于那些可能正在寻找类似东西的人,这是我使用的回调。
multiSource: function(node, data) {
var topMostSelected = data.tree.getSelectedNodes(true);
return topMostSelected;
}