如何回滚无法在jstree中移动的节点

时间:2012-02-02 23:25:46

标签: javascript jquery jstree

我正在尝试弄清楚如何仅回滚未成功移动的文件夹节点。下面的代码是我正在尝试做的一个例子。当您选择了几个文件夹并将它们移动到另一个文件夹时,就会出现问题。如果其中一个目录无法移动,我希望能够将其回滚到原始父目录。 不幸的是,$.jstree.rollback(data.rlbk);会将所有选中的文件夹回滚到之前的位置。

$("#tree").jstree({...}).bind("move_node.jstree", function (e, data) {
    // process all selected nodes directory
    data.rslt.o.each(function (i) {
         // Send request.
         var move = $.parseJSON($.ajax({
             url: "./jstree.php",
             type: 'post',
             async: false,
             data: {
                 operation:  "move_dir",
                 ....
             }
         }).responseText);
         // When everything's ok, the reponseText will be {success: true}
         // In all other cases it won't exist at all.
         if(move.success == undefined){
             // Here I want to rollback the CURRENT failed node.
             // $.jstree.rollback(data.rlbk); will rollback all 
             // of the directories that have been moved.
         }
    }
});

有没有办法做到这一点?

2 个答案:

答案 0 :(得分:2)

我之前看过使用过jstree,但是在我的代码中没有使用它。因此,代码可能不正确,但概念应该是。

根据您的代码,您似乎正在服务器端执行移动操作,并且您希望更新树以反映结果。

基于jsTree文档,看起来好像你无法提交节点更新并回滚到最后一次提交。

您可以回滚树(所有更改)并在之后执行移动,而不是仅回滚您不想要的更改。

为了更好地理解下面的代码,您可能希望阅读它(或创建一个副本),而不需要在“if”语句的条件中设置或引用“wasTriggeredByCode”的行。

$("#tree").jstree({...}).bind("move_node.jstree", function (e, data) {

    var jsTree = $(this);
    var successes = [];

    // Becomes true when function was triggered by code that updates jsTree to
    //  reflect nodes that were successfully moved on the server
    var wasTriggeredByCode = false;

    // process all selected nodes directory
    data.rslt.o.each(function (i) {

         // I'm not certain that this is how the node is referenced
         var node = $(this);

         wasTriggeredByCode = (wasTriggeredByCode || node.data('redoing'));

         // Don't perform server changes when event was triggered from code
         if (wasTriggeredByCode) {
             return;
         }

         // Send request.
         var move = $.parseJSON($.ajax({
             url: "./jstree.php",
             type: 'post',
             async: false,
             data: {
                 operation:  "move_dir",
                 ....
             }
         }).responseText);

         if(move.success){
             successes.push(node);
         }
    });

    // Don't continue when event was triggered from code
    if (wasTriggeredByCode) {
         return;
    }

    // Roll back the tree here
    jsTree.rollback(data.rlbk);

    // Move the nodes
    for (var i=0; i < successes.length; i++) {
        var node = successes[i];

        // According to the documentation this will trigger the move event,
        //  which will result in infinite recursion. To avoid this you'll need
        //  to set a flag or indicate that you're redoing the move.
        node.data('redoing', true);

        jsTree.move_node(node, ...);

        // Remove the flag so that additional moves aren't ignored
        node.removeData('redoing');
    }
});

答案 1 :(得分:1)

我考虑过在jstree中发生类似“ onbeforenodemove”事件的事情,

$("#tree").jstree({...}).bind("before_move_node.jstree", function (e, data) {...}

因此,我查看了jstree.js文件(版本jsTree 3.1.1),并搜索了原始“ move_node.jstree”处理程序的声明。发现它声明了起始行3689:

move_node: function (obj, par, pos, callback, is_loaded, skip_redraw, origin) {...}

此函数的主体末尾包含以下行:

this.trigger('move_node', { "node" : obj, "parent" : new_par.id, "position" : pos, "old_parent" : old_par, "old_position" : old_pos, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this });

上面的行实际上调用了使用.bind(“ move_node.jstree”)声明的回调。 因此,在此函数主体的开头,我添加了以下内容:

var before_data = { "node": obj, "parent": new_par.id, "position": pos, "old_parent": old_par, "old_position": old_pos, 'is_multi': (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign': (!old_ins || !old_ins._id), 'old_instance': old_ins, 'new_instance': this, cancelled: false };
this.trigger('before_move_node', before_data);
if (before_data.cancelled) {
    return false;
}

注意“已取消”:在before_data分配值的末尾为false。

还请注意在分配new_par等值之后插入以上内容。

我页面上的代码(jsTree实例化)现在看起来像这样:

$('#tree')
    .jstree({
        core: {...},
        plugins: [...]
    })
    .bind('before_move_node.jstree', function (e, data) {
        if (...) {
            data.cancelled = true;
        }
    })
传递给'before_move_node.jstree'的

数据对象包含与在标准'move_node.jstree'数据参数中接收到的值相同的值,因此您可以决定要取消还是放弃移动。如果您决定取消,只需将其他“取消”属性设置为true。这样,整个动作就不会发生。