[seda tree / js] Reimplement rules telling which moves are allowed within the js tree
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 11 Dec 2017 16:36:28 +0100
changeset 2913 5205b3490f1c
parent 2912 1715f15e4651
child 2914 ae3705aa2ba7
[seda tree / js] Reimplement rules telling which moves are allowed within the js tree And call the ajax API accordingly. We now allow on top of the earlier "maybeParentOf" mecanism: * to reorder binary / physical data object * to reorder archive units. To do so, we: * turn 'inside' position while moving a node which is already a children node into 'before' + first children as target node, * check if the position is correct, provided that we don't want to mix types: binary objects should be before physical objects which should be before archival units, * call the ajax API by giving it the relative index above mentionned (i.e. index of the node within nodes of the same type).
cubicweb_seda/data/cubes.jqtree.js
cubicweb_seda/data/cubes.seda.js
cubicweb_seda/views/sedatree.py
--- a/cubicweb_seda/data/cubes.jqtree.js	Mon Dec 11 16:28:27 2017 +0100
+++ b/cubicweb_seda/data/cubes.jqtree.js	Mon Dec 11 16:36:28 2017 +0100
@@ -18,6 +18,28 @@
 jqtree = {
     jqTree: function(domid, dragAndDrop, canMoveTo) {
         var $tree = cw.jqNode(domid);
+
+        function adjustPositionAndTarget(position, target_node, moved_node) {
+            if (position === 'inside' && target_node.children.some(e => e.id === moved_node.id)) {
+                position = 'before';
+                target_node = target_node.children[0];
+            }
+            return [position, target_node];
+        }
+
+        function relativeIndex(node) {
+            const children = node.parent.children;
+            let result = 0;
+            for (let idx=0; idx < children.length; idx++) {
+                const child = children[idx];
+                if (child.id === node.id) {
+                    return result;
+                } else if (child.type === node.type) {
+                    result++;
+                }
+            }
+        }
+
         // tree display and basic controls.
         $tree.tree({
             dragAndDrop: dragAndDrop,
@@ -30,6 +52,12 @@
                 return node.maybeMoved;
             },
             onCanMoveTo: function(moved_node, target_node, position) {
+                if ( target_node.id === undefined || position === 'none') {
+                    return false;
+                } else {
+                    const args = adjustPositionAndTarget(position, target_node, moved_node);
+                    position = args[0];
+                    target_node = args[1];
                     return canMoveTo(moved_node, target_node, position);
                 }
             },
@@ -62,7 +90,31 @@
             'tree.move',
             function(event) {
                 event.preventDefault();
-                asyncRemoteExec('jqtree_reparent', move.moved_node.id, target_node.id, 0);
+                const move = event.move_info;
+                function destinationIndex(position, target_node) {
+                    let idx = 0;
+                    if (position === 'after' && target_node.type === move.moved_node.type) {
+                        idx = relativeIndex(target_node) + 1;
+                    }
+                    return idx;
+                }
+
+                const args = adjustPositionAndTarget(move.position, move.target_node, move.moved_node),
+                      position = args[0],
+                      target_node = args[1];
+                if (position === 'inside') {
+                    // this is a reparenting
+                    asyncRemoteExec('jqtree_reparent', move.moved_node.id, target_node.id, 0);
+                } else if (move.moved_node.parent !== target_node.parent) {
+                    // this is a reparenting at specific index
+                    asyncRemoteExec('jqtree_reparent', move.moved_node.id, target_node.parent.id,
+                                    destinationIndex(position, target_node));
+                } else {
+                    // this is an ordering change into the same parent
+                    asyncRemoteExec('jqtree_reorder', move.moved_node.parent.id, move.moved_node.id,
+                                    destinationIndex(position, target_node));
+                }
+
                 // do the move after POSTing.
                 move.do_move();
             }
--- a/cubicweb_seda/data/cubes.seda.js	Mon Dec 11 16:28:27 2017 +0100
+++ b/cubicweb_seda/data/cubes.seda.js	Mon Dec 11 16:36:28 2017 +0100
@@ -30,19 +30,40 @@
     },
 
     canMoveTo: function(moved_node, target_node, position){
-        if ( target_node.id === undefined ) {
-            return false;
-        } else if ( position != 'inside' ) {
-            // moving before/after is not supported
-            return false;
+        if (position === 'after' || position === 'before') {
+            const target_index = target_node.parent.children.indexOf(target_node);
+            if (moved_node.type === 'SEDAArchiveUnit') {
+                // archive unit move
+                // -> OK if before / after another archive unit
+                if (target_node.type === 'SEDAArchiveUnit') {
+                    return true;
+                } else if (target_node.type !== 'SEDAArchiveTransfer') {
+                    // -> OK if it's after the last binary/physical data object before archive unit
+                    if (target_index === target_node.parent.children.length - 1
+                        || target_node.parent.children[target_index + 1].type == 'SEDAArchiveUnit') {
+                        return true;
+                    }
+                }
+                return false;
+            } else {
+                // data object move
+                // -> OK if it's after a data object of the same type
+                //    or if we're moving a physical data object after the last of its kind
+                return (target_node.type === moved_node.type
+                       || (moved_node.type === 'SEDAPhysicalDataObject'
+                           && target_node.type === 'SEDABinaryDataObject'
+                           && target_node.parent.children[target_index + 1].type == 'SEDAPhysicalDataObject'));
+            }
         } else {
-            // avoid moving into the same parent
-            function isMovedNode(element, index, array) {
-                return element.id == moved_node.id;
-            }
-            if ( target_node.children.some(isMovedNode) ) {
+            // special case of moving an archive unit to root: disallow if there
+            // are some data objects since this is visually false, only allow
+            // moving before/after existing children
+            if (target_node.type === 'SEDAArchiveTransfer'
+                && moved_node.type === 'SEDAArchiveUnit'
+                && target_node.children[0].type != 'SEDAArchiveUnit') {
                 return false;
             }
+            // this is a reparenting
             // ensure the new parent target accept the moved node
             return target_node.maybeParentOf.indexOf(moved_node.type) !== -1;
         }
--- a/cubicweb_seda/views/sedatree.py	Mon Dec 11 16:28:27 2017 +0100
+++ b/cubicweb_seda/views/sedatree.py	Mon Dec 11 16:36:28 2017 +0100
@@ -115,7 +115,7 @@
                   & is_instance('SEDABinaryDataObject', 'SEDAPhysicalDataObject'))
 
     def maybe_moved(self):
-        return False
+        return True
 
 
 class SimplifiedBinaryDataObjectIJQTreeAdapter(SEDAIJQTreeAdapter):