Author: jfthomps
Date: Fri Dec  9 16:25:40 2016
New Revision: 1773427

URL: http://svn.apache.org/viewvc?rev=1773427&view=rev
Log:
VCL-1003 - drag and drop support for moving privilege nodes

privilege.php:
-modified viewNodes: 
  -added global javascript variable nodedropdata
  -added continuation to update nodedropdata
  -added javascript connection for onSet on nodestore
  -added ForestStoreModel between store and tree
  -added a bunch of javascript connections to tree
  -added Undo Move button at bottom of tree
  -changed text written vertically for user, user group, and resource groups to 
be done via css instead of generating images
  -added move confirmation dialog
  -added revert move confirmation dialog
-modified selectNode:
  -added Undo Move button at bottom of tree
  -changed text written vertically for user, user group, and resource groups to 
be done via css instead of generating images
  -added javascript to set undo button to be enabled if a move can be undone
-modified JSONprivnodelist2: added parent data to each node
-added nodeDropData
-added AJrefreshNodeDropData
-modified AJsubmitAddChildNode: added $parent as argument to addChildNode
-added AJmoveNode
-added AJsubmitMoveNode
-added AJrevertMoveNode
-modified AJchangeUserPrivs: check if user being modified is logged in user and 
if nodeAdmin, block, or cascade is being changed, if so, include 
refreshNodeDropData() in returned javascript
-modified AJchangeUserGroupPrivs: check if user group being modified is one 
logged in user is a member of and if nodeAdmin, block, or cascade is being 
changed, if so, include refreshNodeDropData() in returned javascript
-modified AJsubmitAddUserPriv: check if submitted user is logged in user and if 
nodeAdmin, block, or cascade is being added, if so, include 
refreshNodeDropData() in returned javascript
-modified AJsubmitAddUserGroupPriv: check if user group being added is one 
logged in user is a member of and if nodeAdmin, block, or cascade is being 
added, if so, include refreshNodeDropData() in returned javascript

utils.php:
-removed getImageText
-modified getDojoHTML: added dijit.tree.ForestStoreModel and 
dijit.tree.dndSource to $dojoRequires for viewNodes; added javascript for 
dojo.connect for onmouseup to document under case 'viewNodes'

states.php:
-added AJmoveNode
-added AJsubmitMoveNode
-added AJrevertMoveNode
-added AJrefreshNodeDropData

vcl.css:
-added th.privheader
-added th.privheader > div

privilege.js:
-added several globals: saveMoveNode, moveitem, nomove, dragnode, mouseontree, 
dragging, moveData object
-general changes in several functions:
  -removed some old commented out code
  -reworked how selected node is being displayed as selected, previously this 
was done by adding and removing the privtreeselected class; now using 
tree.attr('path') to set and get the selected node (this is the more proper way)
  -changed references to tree.store to refer to tree.model.store since the 
ForestStoreModel was added between them
-added mouseDown
-added mouseRelease
-modified addChildNode: added parentid as an additional argument; include 
parentid when calling store.newItem; added call to positionNode so that node 
gets put in the right sort order in the tree; add an entry to nodedropdata for 
the new node
-added positionNode
-modified removeNodesFromTree: added code to set the Undo Move button to 
disabled if the previous parent of the moved node is the one being removed
-modified removeNodesFromTreeCB: wrapped call to deleteItem with setting nomove 
to 1 and back to 0 so that moveNode just returns when invoked by the call to 
deleteItem
-modified renameNode: added code to put focus on submitRenameNodeBtn, if enter 
was used to submit the new name while the focus was on the text box, the new 
value of the text box was not saved in the widget and the old name was getting 
submitted; set focus back on text box if the name wasn't actually changed in 
the text box
-modified renameNodeCB: wrapped setValue with setting nomove to 0 and back to 1 
so moveNode just returns when invoked by the call to setValue; added setTimeout 
to reposition node based on new name after half a second
-added moveNode
-added moveNodeCB
-added submitMoveNode
-added submitMoveNodeCB
-added submitRevertMoveNode
-added submitRevertMoveNodeCB
-added revertNodeMove
-added revertNodeMoveCB
-added setSelected
-added checkCanMove
-added checkNodeDrop
-added refreshNodeDropData

deleted images/textimage.php - changed code calling this to use css to write 
text vertically

Removed:
    vcl/trunk/web/images/textimage.php
Modified:
    vcl/trunk/web/.ht-inc/privileges.php
    vcl/trunk/web/.ht-inc/states.php
    vcl/trunk/web/.ht-inc/utils.php
    vcl/trunk/web/css/vcl.css
    vcl/trunk/web/js/privileges.js

Modified: vcl/trunk/web/.ht-inc/privileges.php
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/privileges.php?rev=1773427&r1=1773426&r2=1773427&view=diff
==============================================================================
--- vcl/trunk/web/.ht-inc/privileges.php (original)
+++ vcl/trunk/web/.ht-inc/privileges.php Fri Dec  9 16:25:40 2016
@@ -58,10 +58,24 @@ function viewNodes() {
                print "<div id=\"privtreetab\" 
dojoType=\"dijit.layout.ContentPane\" title=\"Privilege Tree\">\n";
        }
        print "<H2>Privilege Tree</H2>\n";
+       print "<script type=\"text/javascript\">\n";
+       $nodedrop = nodeDropData();
+       print "var $nodedrop";
+       print "</script>\n";
+       $cont = addContinuationsEntry('AJrefreshNodeDropData');
+       print "<INPUT type=hidden id=refreshnodedropdatacont 
value=\"$cont\"\n>";
        $cont = addContinuationsEntry('JSONprivnodelist');
-       print "<div dojoType=\"dojo.data.ItemFileWriteStore\" url=\"" . BASEURL 
. SCRIPT . "?continuation=$cont\" jsid=\"nodestore\" id=\"nodestore\"></div>\n";
+       print "<div dojoType=\"dojo.data.ItemFileWriteStore\" url=\"" . BASEURL 
. SCRIPT . "?continuation=$cont\" jsId=\"nodestore\" id=\"nodestore\">\n";
+       print "  <script type=\"dojo/connect\" event=\"onSet\" 
args=\"node\">\n";
+       print "     moveNode(node);\n";
+       print "  </script>\n";
+       print "</div>\n";
+       $cont = addContinuationsEntry('AJmoveNode');
+       print "<INPUT type=hidden id=movenodecont value=\"$cont\"\n>";
        print "<div class=privtreediv>\n";
-       print "<div dojoType=\"dijit.Tree\" store=\"nodestore\" 
showRoot=\"false\" id=privtree>\n";
+       print "<div dojoType=\"dijit.tree.ForestStoreModel\" jsId=\"nodemodel\" 
store=\"nodestore\" query=\"{name: '*'}\"></div>\n";
+       print "<div id=\"privtreeparent\">\n";
+       print "<div dojoType=\"dijit.Tree\" model=\"nodemodel\" 
showRoot=\"false\" id=privtree dndController=\"dijit.tree.dndSource\">\n";
        print "  <script type=\"dojo/connect\" event=\"focusNode\" 
args=\"node\">\n";
        print "    nodeSelect(node);\n";
        print "  </script>\n";
@@ -78,19 +92,42 @@ function viewNodes() {
        print "    }else{\n";
        print "      this._expandNode(node);\n";
        print "    }\n";
-       print "    if(addclass || node.item.name == focusid)\n";
-       print "      dojo.addClass(node.labelNode, 'privtreeselected');\n";
        print "  </script>\n";
        print "  <script type=\"dojo/connect\" event=\"startup\" 
args=\"item\">\n";
        print "    focusFirstNode($activeNode);\n";
        print "  </script>\n";
+       print "  <script type=\"dojo/method\" event=\"checkAcceptance\" 
args=\"tree, domnodes\">\n";
+       print "    return checkCanMove(tree, domnodes);\n";
+       print "  </script>\n";
+       print "  <script type=\"dojo/method\" event=\"checkItemAcceptance\" 
args=\"domnode, tree, position\">\n";
+       print "    return checkNodeDrop(domnode, tree, position);\n";
+       print "  </script>\n";
+       print "  <script type=\"dojo/connect\" event=\"_onNodeMouseEnter\" 
args=\"item, evt\">\n";
+       print "    dragnode.hoverid = item.item.name[0];\n";
+       print "  </script>\n";
+       print "  <script type=\"dojo/connect\" event=\"_onNodeMouseLeave\" 
args=\"item, evt\">\n";
+       print "    dragnode.hoverid = 0;\n";
+       print "  </script>\n";
+       print "  <script type=\"dojo/connect\" event=\"onMouseDown\" 
args=\"evt\">\n";
+       print "    mouseDown(evt);\n";
+       print "  </script>\n";
+       print "  <script type=\"dojo/connect\" event=\"onMouseUp\" 
args=\"evt\">\n";
+       print "    mouseRelease(evt);\n";
+       print "  </script>\n";
+       print "  <script type=\"dojo/connect\" event=\"onMouseLeave\" 
args=\"evt\">\n";
+       print "    mouseontree = 0;\n";
+       print "  </script>\n";
+       print "  <script type=\"dojo/connect\" event=\"onMouseEnter\" 
args=\"evt\">\n";
+       print "    mouseontree = 1;\n";
+       print "  </script>\n";
        print "</div>\n";
+       print "</div>\n"; # privtreeparent
        print "</div>\n";
        print "<div id=treebuttons>\n";
+       print "<TABLE summary=\"\" cellspacing=\"\" cellpadding=\"\">\n";
+       print "  <TR valign=top>\n";
        if($hasNodeAdmin) {
-               print "<TABLE summary=\"\" cellspacing=\"\" 
cellpadding=\"\">\n";
-               print "  <TR valign=top>\n";
-               print "    <TD><FORM action=\"" . BASEURL . SCRIPT . "\" 
method=post>\n";
+               print "    <TD>\n";
                print "    <button id=addNodeBtn 
dojoType=\"dijit.form.Button\">\n";
                print "      Add Child\n";
                print "      <script type=\"dojo/method\" event=onClick>\n";
@@ -98,8 +135,8 @@ function viewNodes() {
                print "        return false;\n";
                print "      </script>\n";
                print "    </button>\n";
-               print "    </FORM></TD>\n";
-               print "    <TD><FORM action=\"" . BASEURL . SCRIPT . "\" 
method=post>\n";
+               print "    </TD>\n";
+               print "    <TD>\n";
                print "    <button id=deleteNodeBtn 
dojoType=\"dijit.form.Button\">\n";
                print "      Delete Node and Children\n";
                print "      <script type=\"dojo/method\" event=onClick>\n";
@@ -107,8 +144,8 @@ function viewNodes() {
                print "        return false;\n";
                print "      </script>\n";
                print "    </button>\n";
-               print "    </FORM></TD>\n";
-               print "    <TD><FORM action=\"" . BASEURL . SCRIPT . "\" 
method=post>\n";
+               print "    </TD>\n";
+               print "    <TD>\n";
                print "    <button id=renameNodeBtn 
dojoType=\"dijit.form.Button\">\n";
                print "      Rename Node\n";
                print "      <script type=\"dojo/method\" event=onClick>\n";
@@ -116,11 +153,18 @@ function viewNodes() {
                print "        return false;\n";
                print "      </script>\n";
                print "    </button>\n";
-               print "    </FORM></TD>\n";
-               print "    <td></td>\n";
-               print "  </TR>\n";
-               print "</TABLE>\n";
+               print "    </TD>\n";
        }
+       print "    <td>\n";
+       print "    <button id=\"revertMoveNodeBtn\" 
dojoType=\"dijit.form.Button\" disabled=\"true\">\n";
+       print "      Undo Move\n";
+       print "      <script type=\"dojo/method\" event=onClick>\n";
+       print "        dijit.byId('revertMoveNodeDlg').show();\n";
+       print "      </script>\n";
+       print "    </button>\n";
+       print "    </td>\n";
+       print "  </TR>\n";
+       print "</TABLE>\n";
        print "</div>\n";
        $cont = addContinuationsEntry('selectNode');
        print "<INPUT type=hidden id=nodecont value=\"$cont\">\n";
@@ -128,7 +172,6 @@ function viewNodes() {
        # privileges
        print "<H2>Privileges at Selected Node</H2>\n";
        $node = $activeNode;
-
        $nodeInfo = getNodeInfo($node);
        $privs = getNodePrivileges($node);
        $cascadePrivs = getNodeCascadePrivileges($node);
@@ -156,8 +199,7 @@ function viewNodes() {
                foreach($usertypes["users"] as $type) {
                        if($type == 'configAdmin')
                                continue;
-                       $img = getImageText($type);
-                       print "    <TD>$img</TD>\n";
+                       print "    <TH 
class=\"privheader\"><div><span>$type</span></div></TH>\n";
                }
                print "  </TR>\n";
                $users = array_unique(array_merge(array_keys($privs["users"]), 
@@ -205,8 +247,7 @@ function viewNodes() {
                foreach($usertypes["users"] as $type) {
                        if($type == 'configAdmin')
                                continue;
-                       $img = getImageText($type);
-                       print "    <TH>$img</TH>\n";
+                       print "    <TH 
class=\"privheader\"><div><span>$type</span></div></TH>\n";
                }
                print "  </TR>\n";
                $groupids = 
array_unique(array_merge(array_keys($privs["usergroups"]), 
@@ -266,8 +307,7 @@ function viewNodes() {
                foreach($resourcetypes as $type) {
                        if($type == 'block' || $type == 'cascade')
                                continue;
-                       $img = getImageText("$type");
-                       print "    <TH>$img</TH>\n";
+                       print "    <TH 
class=\"privheader\"><div><span>$type</span></div></TH>\n";
                }
                print "  </TR>\n";
                $resources = 
array_unique(array_merge(array_keys($privs["resources"]), 
@@ -327,10 +367,8 @@ function viewNodes() {
        print "    <TD></TD>\n";
        print "    <TH class=\"privBlock\" bgcolor=gray style=\"color: 
black;\">Block<br>Cascaded<br>Rights</TH>\n";
        print "    <TH class=\"privCascade\" bgcolor=\"#008000\" style=\"color: 
black;\">Cascade<br>to Child<br>Nodes</TH>\n";
-       foreach($usertypes["users"] as $type) {
-               $img = getImageText($type);
-               print "    <TD>$img</TD>\n";
-       }
+       foreach($usertypes["users"] as $type)
+               print "    <TH 
class=\"privheader\"><div><span>$type</span></div></TH>\n";
        print "  </TR>\n";
        print "  <TR>\n";
        print "    <TD><INPUT type=text id=newuser name=newuser size=15";
@@ -393,10 +431,8 @@ function viewNodes() {
        print "    <TD></TD>\n";
        print "    <TH class=\"privBlock\" bgcolor=gray style=\"color: 
black;\">Block<br>Cascaded<br>Rights</TH>\n";
        print "    <TH class=\"privCascade\" bgcolor=\"#008000\" style=\"color: 
black;\">Cascade<br>to Child<br>Nodes</TH>\n";
-       foreach($usertypes["users"] as $type) {
-               $img = getImageText($type);
-               print "    <TD>$img</TD>\n";
-       }
+       foreach($usertypes["users"] as $type)
+               print "    <TH 
class=\"privheader\"><div><span>$type</span></div></TH>\n";
        print "  </TR>\n";
        print "  <TR>\n";
        print "    <TD>\n";
@@ -464,8 +500,7 @@ function viewNodes() {
        foreach($resourcetypes as $type) {
                if($type == 'block' || $type == 'cascade')
                        continue;
-               $img = getImageText("$type");
-               print "    <TH>$img</TH>\n";
+               print "    <TH 
class=\"privheader\"><div><span>$type</span></div></TH>\n";
        }
        print "  </TR>\n";
        print "  <TR>\n";
@@ -636,6 +671,71 @@ function viewNodes() {
        print "</div>\n";
        print "</div>\n";
 
+       print "<div dojoType=dijit.Dialog\n";
+       print "     id=moveDialog\n";
+       print "     title=\"Move Node(s)\"\n";
+       print "     duration=250\n";
+       print "     draggable=true>\n";
+       print "Move the following node and all of its children?<br><br>\n";
+       print "<label for=moveNodeName>Node:</label>\n";
+       print "<span id=moveNodeName></span><br>\n";
+       print "<label for=moveNodeOldParentName>Old Parent:</label>\n";
+       print "<span id=moveNodeOldParentName></span><br>\n";
+       print "<label for=moveNodeNewParentName>New Parent:</label>\n";
+       print "<span id=moveNodeNewParentName></span><br><br>\n";
+       print "<div align=center>\n";
+       print "<TABLE summary=\"\"><TR>\n";
+       print "<TD>\n";
+       print "  <button id=submitMoveNodeBtn 
dojoType=\"dijit.form.Button\">\n";
+       print "    Move Node(s)\n";
+       print "    <script type=\"dojo/method\" event=onClick>\n";
+       print "      submitMoveNode();\n";
+       print "    </script>\n";
+       print "  </button>\n";
+       print "</TD>\n";
+       print "<TD>\n";
+       print "  <button id=cancelMoveNodeBtn 
dojoType=\"dijit.form.Button\">\n";
+       print "    Cancel\n";
+       print "    <script type=\"dojo/method\" event=onClick>\n";
+       print "      revertNodeMove();\n";
+       print "      dijit.byId('moveDialog').hide();\n";
+       print "    </script>\n";
+       print "  </button>\n";
+       print "</TD>\n";
+       print "</TR></TABLE>\n";
+       print "<INPUT type=hidden id=movenodesubmitcont>\n";
+       print "</div>\n";
+       print "</div>\n";
+
+       print "<div dojoType=dijit.Dialog\n";
+       print "     id=revertMoveNodeDlg\n";
+       print "     title=\"Undo Move Node(s)\"\n";
+       print "     duration=250\n";
+       print "     draggable=true>\n";
+       print "Undo the previous node move?<br><br>\n";
+       print "<div align=center>\n";
+       print "<TABLE summary=\"\"><TR>\n";
+       print "<TD>\n";
+       print "  <button id=submitRevertMoveNodeBtn 
dojoType=\"dijit.form.Button\">\n";
+       print "    Undo Move\n";
+       print "    <script type=\"dojo/method\" event=onClick>\n";
+       print "      submitRevertMoveNode();\n";
+       print "    </script>\n";
+       print "  </button>\n";
+       print "</TD>\n";
+       print "<TD>\n";
+       print "  <button dojoType=\"dijit.form.Button\">\n";
+       print "    Cancel\n";
+       print "    <script type=\"dojo/method\" event=onClick>\n";
+       print "      dijit.byId('revertMoveNodeDlg').hide();\n";
+       print "    </script>\n";
+       print "  </button>\n";
+       print "</TD>\n";
+       print "</TR></TABLE>\n";
+       print "<INPUT type=\"hidden\" id=\"revertmovenodecont\">\n";
+       print "</div>\n";
+       print "</div>\n";
+
        print "<div dojoType=dijit.Dialog id=workingDialog duration=250 
refocus=False>\n";
        print "Loading...\n";
        print "  <script type=\"dojo/connect\" event=_setup>\n";
@@ -732,9 +832,9 @@ function selectNode() {
        $hasNodeAdmin = checkUserHasPriv("nodeAdmin", $user["id"], $node, 
$privs,
                                         $cascadePrivs);
 
+       $text .= "<TABLE>";
+       $text .= "  <TR valign=top>";
        if($hasNodeAdmin) {
-               $text .= "<TABLE>";
-               $text .= "  <TR valign=top>";
                $text .= "    <TD><FORM action=\"" . BASEURL . SCRIPT . "\" 
method=post>";
                $text .= "    <button id=addNodeBtn 
dojoType=\"dijit.form.Button\">";
                $text .= "      Add Child";
@@ -762,12 +862,21 @@ function selectNode() {
                $text .= "      </script>";
                $text .= "    </button>";
                $text .= "    </FORM></TD>";
-               $text .= "  </TR>";
-               $text .= "</TABLE>";
        }
+       $text .= "    <td>";
+       $text .= "    <button id=\"revertMoveNodeBtn\" 
dojoType=\"dijit.form.Button\" disabled=\"true\">";
+       $text .= "      Undo Move";
+       $text .= "      <script type=\"dojo/method\" event=onClick>";
+       $text .= "        dijit.byId(\"revertMoveNodeDlg\").show();";
+       $text .= "      </script>";
+       $text .= "    </button>";
+       $text .= "    </td>";
+       $text .= "  </TR>";
+       $text .= "</TABLE>";
        $return .= "if(dijit.byId('addNodeBtn')) 
dijit.byId('addNodeBtn').destroy();";
        $return .= "if(dijit.byId('deleteNodeBtn')) 
dijit.byId('deleteNodeBtn').destroy();";
        $return .= "if(dijit.byId('renameNodeBtn')) 
dijit.byId('renameNodeBtn').destroy();";
+       $return .= "if(dijit.byId('revertMoveNodeBtn')) 
dijit.byId('revertMoveNodeBtn').destroy();";
        $return .= setAttribute('treebuttons', 'innerHTML', $text);
        $return .= "AJdojoCreate('treebuttons');";
 
@@ -783,10 +892,8 @@ function selectNode() {
                $text .= "    <TD></TD>";
                $text .= "    <TH class=\"privBlock\" bgcolor=gray 
style=\"color: black;\">Block<br>Cascaded<br>Rights</TH>";
                $text .= "    <TH class=\"privCascade\" bgcolor=\"#008000\" 
style=\"color: black;\">Cascade<br>to Child<br>Nodes</TH>";
-               foreach($usertypes["users"] as $type) {
-                       $img = getImageText($type);
-                       $text .= "    <TD>$img</TD>";
-               }
+               foreach($usertypes["users"] as $type)
+                       $text .= "    <TH 
class=\"privheader\"><div><span>$type</span></div></TH>";
                $text .= "  </TR>";
                $users = array_unique(array_merge(array_keys($privs["users"]), 
                                      array_keys($cascadePrivs["users"])));
@@ -833,10 +940,8 @@ function selectNode() {
                $text .= "    <TD></TD>";
                $text .= "    <TH class=\"privBlock\" bgcolor=gray 
style=\"color: black;\">Block<br>Cascaded<br>Rights</TH>";
                $text .= "    <TH class=\"privCascade\" bgcolor=\"#008000\" 
style=\"color: black;\">Cascade<br>to Child<br>Nodes</TH>";
-               foreach($usertypes["users"] as $type) {
-                       $img = getImageText($type);
-                       $text .= "    <TH>$img</TH>";
-               }
+               foreach($usertypes["users"] as $type)
+                       $text .= "    <TH 
class=\"privheader\"><div><span>$type</span></div></TH>";
                $text .= "  </TR>";
                $groupids = 
array_unique(array_merge(array_keys($privs["usergroups"]), 
                                         
array_keys($cascadePrivs["usergroups"])));
@@ -898,8 +1003,7 @@ function selectNode() {
                foreach($resourcetypes as $type) {
                        if($type == 'block' || $type == 'cascade')
                                continue;
-                       $img = getImageText("$type");
-                       $text .= "    <TH>$img</TH>";
+                       $text .= "    <TH 
class=\"privheader\"><div><span>$type</span></div></TH>";
                }
                $text .= "  </TR>";
                $resources = 
array_unique(array_merge(array_keys($privs["resources"]), 
@@ -943,6 +1047,9 @@ function selectNode() {
        $return .= setAttribute('resourcesDiv', 'innerHTML', $text);
        $return .= "AJdojoCreate('resourcesDiv');";
 
+       $js .= "if(typeof moveitem != 'undefined') ";
+       $js .= "{dijit.byId('revertMoveNodeBtn').set('disabled', false);}";
+
        print $return;
        print $js;
 }
@@ -977,7 +1084,8 @@ function JSONprivnodelist() {
 function JSONprivnodelist2($nodelist) {
        $data = '';
        foreach(array_keys($nodelist) as $id) {
-               $data .= "{name:'$id', display:'{$nodelist[$id]['name']}' ";
+               $nodeinfo = getNodeInfo($id);
+               $data .= "{name:'$id', display:'{$nodelist[$id]['name']}', 
parent:'{$nodeinfo['parent']}'";
                $children = getChildNodes($id);
                if(count($children))
                        $data .= ", children: [ " . 
JSONprivnodelist2($children) . "]},";
@@ -990,6 +1098,44 @@ function JSONprivnodelist2($nodelist) {
 
 
////////////////////////////////////////////////////////////////////////////////
 ///
+/// \fn nodeDropData()
+///
+/// \return string for setting value of nodedropdata to a javascript object
+///
+/// \brief generates a string to define a javascript object that contains all
+/// privtree node ids with each having a value of 0 or 1 depending on whether 
or
+/// not they can be moved and dropped on
+///
+////////////////////////////////////////////////////////////////////////////////
+function nodeDropData() {
+       global $user;
+       $query = "SELECT id, parent FROM privnode WHERE id > " . 
DEFAULT_PRIVNODE;
+       $qh = doQuery($query);
+       $data = 'nodedropdata = {';
+       while($row = mysql_fetch_assoc($qh))
+               if(checkUserHasPriv('nodeAdmin', $user['id'], $row['id']) &&
+                  ($row['parent'] == DEFAULT_PRIVNODE || 
checkUserHasPriv('nodeAdmin', $user['id'], $row['parent'])))
+                       $data .= "{$row['id']}: '1',";
+               else
+                       $data .= "{$row['id']}: '0',";
+       rtrim($data, ',');
+       $data .= '}';
+       return $data;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn AJrefreshNodeDropData()
+///
+/// \brief prints output from nodeDropData
+///
+////////////////////////////////////////////////////////////////////////////////
+function AJrefreshNodeDropData() {
+       print nodeDropData();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
 /// \fn AJsubmitAddChildNode()
 ///
 /// \brief processes input for adding a child node; if all is ok, adds node
@@ -1051,7 +1197,7 @@ function AJsubmitAddChildNode() {
                array_push($privs, "cascade");
                updateUserOrGroupPrivs($user["id"], $nodeid, $privs, array(), 
"user");
        }
-       print "addChildNode('$newnode', $nodeid);";
+       print "addChildNode('$newnode', $nodeid, $parent);";
 }
 
 
////////////////////////////////////////////////////////////////////////////////
@@ -1177,6 +1323,123 @@ function AJsubmitRenameNode() {
 
 
////////////////////////////////////////////////////////////////////////////////
 ///
+/// \fn AJmoveNode()
+///
+/// \brief handles saving a moved node
+///
+////////////////////////////////////////////////////////////////////////////////
+function AJmoveNode() {
+       global $user;
+       $moveid = processInputVar('moveid', ARG_NUMERIC);
+       $oldparentid = processInputVar('oldparentid', ARG_NUMERIC);
+       $newparentid = processInputVar('newparentid', ARG_NUMERIC);
+
+       if(! checkUserHasPriv("nodeAdmin", $user["id"], $moveid) ||
+          ! checkUserHasPriv("nodeAdmin", $user["id"], $newparentid) ||
+          ! checkUserHasPriv("nodeAdmin", $user["id"], $oldparentid)) {
+               $arr = array('status' => 'noaccess',
+                            'moveid' => $moveid,
+                            'oldparentid' => $oldparentid,
+                            'newparentid' => $newparentid);
+               sendJSON($arr);
+               return;
+       }
+
+       if($oldparentid == $newparentid) {
+               $arr = array('status' => 'nochange');
+               sendJSON($arr);
+               return;
+       }
+
+       # check for name collision at parent
+       $query = "SELECT p2.id "
+              . "FROM privnode p1, "
+              .      "privnode p2 "
+              . "WHERE p1.id = $moveid AND "
+              .       "p2.parent = $newparentid AND "
+              .       "p2.name = p1.name";
+       $qh = doQuery($query);
+       if($row = mysql_num_rows($qh)) {
+               $arr = array('status' => 'collision',
+                            'moveid' => $moveid,
+                            'oldparentid' => $oldparentid,
+                            'newparentid' => $newparentid);
+               sendJSON($arr);
+               return;
+       }
+
+       $nodeinfo = getNodeInfo($moveid);
+       $oldnodeinfo = getNodeInfo($oldparentid);
+       $newnodeinfo = getNodeInfo($newparentid);
+       $cdata = array('moveid' => $moveid,
+                      'newparentid' => $newparentid,
+                      'oldparentid' => $oldparentid);
+       $cont = addContinuationsEntry('AJsubmitMoveNode', $cdata, 300);
+       $revertcont = addContinuationsEntry('AJrevertMoveNode', $cdata);
+       $arr = array('status' => 'success',
+                    'movename' => $nodeinfo['name'],
+                    'oldparent' => $oldnodeinfo['name'],
+                    'newparent' => $newnodeinfo['name'],
+                    'moveid' => $moveid,
+                    'oldparentid' => $oldparentid,
+                    'newparentid' => $newparentid,
+                    'continuation' => $cont,
+                    'revertcont' => $revertcont);
+       sendJSON($arr);
+       return;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn AJsubmitMoveNode()
+///
+/// \brief handles saving a moved node
+///
+////////////////////////////////////////////////////////////////////////////////
+function AJsubmitMoveNode() {
+       $moveid = getContinuationVar('moveid');
+       $newparentid = getContinuationVar('newparentid');
+       $oldparentid = getContinuationVar('oldparentid');
+
+       $query = "UPDATE privnode "
+              . "SET parent = $newparentid "
+              . "WHERE id = $moveid AND "
+              .       "parent = $oldparentid";
+       doQuery($query);
+
+       clearPrivCache();
+
+       $arr = array('status' => 'success',
+                    'newparentid' => $newparentid);
+       sendJSON($arr);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn AJrevertMoveNode()
+///
+/// \brief handles reverting a moved node
+///
+////////////////////////////////////////////////////////////////////////////////
+function AJrevertMoveNode() {
+       $moveid = getContinuationVar('moveid');
+       $newparentid = getContinuationVar('newparentid');
+       $oldparentid = getContinuationVar('oldparentid');
+
+       $query = "UPDATE privnode "
+              . "SET parent = $oldparentid "
+              . "WHERE id = $moveid AND "
+              .       "parent = $newparentid";
+       doQuery($query);
+
+       clearPrivCache();
+
+       $arr = array('status' => 'success');
+       sendJSON($arr);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
 /// \fn userLookup()
 ///
 /// \brief prints a page to display a user's privileges
@@ -2815,6 +3078,9 @@ function AJchangeUserPrivs() {
        }
        updateUserOrGroupPrivs($newuser, $node, $adds, $removes, "user");
        $_SESSION['dirtyprivs'] = 1;
+       $userid = getUserlistID($newuser);
+       if($userid == $user['id'] && in_array($newpriv, array('nodeAdmin', 
'block', 'cascade')))
+               print "refreshNodeDropData();";
 }
 
 
////////////////////////////////////////////////////////////////////////////////
@@ -2870,6 +3136,9 @@ function AJchangeUserGroupPrivs() {
        }
        updateUserOrGroupPrivs($newusergrpid, $node, $adds, $removes, "group");
        $_SESSION['dirtyprivs'] = 1;
+       if(array_key_exists($newusergrpid, $user['groups']) &&
+          in_array($newpriv, array('nodeAdmin', 'block', 'cascade')))
+               print "refreshNodeDropData();";
 }
 
 
////////////////////////////////////////////////////////////////////////////////
@@ -2993,6 +3262,12 @@ function AJsubmitAddUserPriv() {
        clearPrivCache();
        print "refreshPerms(); ";
        print "addUserPaneHide(); ";
+       $userid = getUserlistID($newuser);
+       if($userid == $user['id'] && 
+          (in_array('nodeAdmin', $perms) ||
+          in_array('cascade', $perms) ||
+          in_array('block', $perms)))
+               print nodeDropData();
 }
 
 
////////////////////////////////////////////////////////////////////////////////
@@ -3042,6 +3317,11 @@ function AJsubmitAddUserGroupPriv() {
        clearPrivCache();
        print "refreshPerms(); ";
        print "addUserGroupPaneHide(); ";
+       if(array_key_exists($newgroupid, $user['groups']) &&
+          (in_array('nodeAdmin', $perms) ||
+          in_array('cascade', $perms) ||
+          in_array('block', $perms)))
+               print nodeDropData();
 }
 
 
////////////////////////////////////////////////////////////////////////////////

Modified: vcl/trunk/web/.ht-inc/states.php
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/states.php?rev=1773427&r1=1773426&r2=1773427&view=diff
==============================================================================
--- vcl/trunk/web/.ht-inc/states.php (original)
+++ vcl/trunk/web/.ht-inc/states.php Fri Dec  9 16:25:40 2016
@@ -79,6 +79,10 @@ $noHTMLwrappers = array('sendRDPfile',
                         'AJsubmitAddChildNode',
                         'AJsubmitDeleteNode',
                         'AJsubmitRenameNode',
+                        'AJmoveNode',
+                        'AJsubmitMoveNode',
+                        'AJrevertMoveNode',
+                        'AJrefreshNodeDropData',
                         'AJupdateWaitTime',
                         'AJviewRequests',
                         'AJnewRequest',
@@ -418,6 +422,10 @@ $actions['mode']['AJsubmitAddChildNode']
 $actions['mode']['submitDeleteNode'] = "submitDeleteNode";
 $actions['mode']['AJsubmitDeleteNode'] = "AJsubmitDeleteNode";
 $actions['mode']['AJsubmitRenameNode'] = "AJsubmitRenameNode";
+$actions['mode']['AJmoveNode'] = "AJmoveNode";
+$actions['mode']['AJsubmitMoveNode'] = "AJsubmitMoveNode";
+$actions['mode']['AJrevertMoveNode'] = "AJrevertMoveNode";
+$actions['mode']['AJrefreshNodeDropData'] = "AJrefreshNodeDropData";
 $actions['mode']['viewNodePrivs'] = "viewNodePrivs";
 $actions['mode']['selectNode'] = "selectNode";
 $actions['mode']['changeUserPrivs'] = "changeUserPrivs";
@@ -447,6 +455,10 @@ $actions['pages']['AJsubmitAddChildNode'
 $actions['pages']['submitDeleteNode'] = "privileges";
 $actions['pages']['AJsubmitDeleteNode'] = "privileges";
 $actions['pages']['AJsubmitRenameNode'] = "privileges";
+$actions['pages']['AJmoveNode'] = "privileges";
+$actions['pages']['AJsubmitMoveNode'] = "privileges";
+$actions['pages']['AJrevertMoveNode'] = "privileges";
+$actions['pages']['AJrefreshNodeDropData'] = "privileges";
 $actions['pages']['viewNodePrivs'] = "privileges";
 $actions['pages']['selectNode'] = "privileges";
 $actions['pages']['changeUserPrivs'] = "privileges";

Modified: vcl/trunk/web/.ht-inc/utils.php
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/utils.php?rev=1773427&r1=1773426&r2=1773427&view=diff
==============================================================================
--- vcl/trunk/web/.ht-inc/utils.php (original)
+++ vcl/trunk/web/.ht-inc/utils.php Fri Dec  9 16:25:40 2016
@@ -11320,22 +11320,6 @@ function timeToNextReservation($request)
 
 
////////////////////////////////////////////////////////////////////////////////
 ///
-/// \fn getImageText($text)
-///
-/// \param $text - text to be in the image
-///
-/// \return a text string
-///
-/// \brief creates an image src line that calls textimage.php to print an
-/// image with $text in it
-///
-////////////////////////////////////////////////////////////////////////////////
-function getImageText($text) {
-       return "<img alt=\"$text\" src=\"" . BASEURL . 
"/images/textimage.php?text=$text\">";
-}
-
-////////////////////////////////////////////////////////////////////////////////
-///
 /// \fn weekOfYear($ts)
 ///
 /// \param $ts - unix timestamp
@@ -12964,6 +12948,8 @@ function getDojoHTML($refresh) {
                        $dojoRequires = array('dojo.parser',
                                              'dojo.data.ItemFileWriteStore',
                                              'dijit.Tree',
+                                             'dijit.tree.ForestStoreModel',
+                                             'dijit.tree.dndSource',
                                              'dijit.form.Button',
                                              'dijit.form.CheckBox',
                                              'dijit.form.TextBox',
@@ -13555,6 +13541,7 @@ function getDojoHTML($refresh) {
                        foreach($dojoRequires as $req)
                                $rt .= "   dojo.require(\"$req\");\n";
                        $rt .= "      document.onmousemove = updateMouseXY;\n";
+                       $rt .= "      dojo.connect(document, 'onmouseup', 
mouseRelease);\n";
                        $rt .= "   });\n";
                        $rt .= "</script>\n";
                        return $rt;

Modified: vcl/trunk/web/css/vcl.css
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/css/vcl.css?rev=1773427&r1=1773426&r2=1773427&view=diff
==============================================================================
--- vcl/trunk/web/css/vcl.css (original)
+++ vcl/trunk/web/css/vcl.css Fri Dec  9 16:25:40 2016
@@ -658,3 +658,17 @@ body {
        text-align: right;
        padding-right: 0.5em;
 }
+
+th.privheader {
+       height: 155px;
+       white-space: nowrap;
+}
+
+th.privheader > div {
+       transform:
+         translate(0px, 60px)
+         rotate(270deg);
+       width: 15px;
+       font-weight: bold;
+       font-size: 1.2em;
+}

Modified: vcl/trunk/web/js/privileges.js
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/js/privileges.js?rev=1773427&r1=1773426&r2=1773427&view=diff
==============================================================================
--- vcl/trunk/web/js/privileges.js (original)
+++ vcl/trunk/web/js/privileges.js Fri Dec  9 16:25:40 2016
@@ -15,6 +15,24 @@
 * limitations under the License.
 */
 var currentOver = '';
+var saveMoveNode = 0;
+var moveitem;
+var nomove = 0;
+var dragnode = {hoverid: 0, dragid: 0, startX: 0, startY: 0};
+var mouseontree = 0;
+var dragging = 0;
+
+function moveData() {
+       this.oldparentid = '';
+       this.oldparentobj = '';
+       this.oldparentset = 0;
+       this.newparentid = '';
+       this.newparentobj = '';
+       this.newparentset = 0;
+       this.moveid = '';
+       this.moveobj = '';
+       this.moveset = 0;
+}
 
 function generalPrivCB(data, ioArgs) {
        eval(data);
@@ -26,7 +44,6 @@ function setLoading2(duration) {
    document.body.style.cursor = 'wait';
        if(dijit.byId('workingDialog')) {
                var obj = dijit.byId('workingDialog');
-               //dojo.addClass(obj.titleBar, 'hidden');
                obj.show();
        }
 }
@@ -41,7 +58,6 @@ function nodeSelect(node) {
        /* for some reason, _onLabelFocus does not get set up for tree nodes by
         * Safari; so, we perform the same operations here */
        if(dojo.isSafari) {
-               //dojo.addClass(node.labelNode, "dijitTreeLabelFocused");
                node.tree._onNodeFocus(node);
        }
        var nodeid = node.item.name;
@@ -49,16 +65,9 @@ function nodeSelect(node) {
                return;
        var nodename = node.item.display;
        var tree = dijit.byId('privtree');
-       if(tree.lastLabel)
-               dojo.removeClass(tree.lastLabel, 'privtreeselected');
-       tree.lastLabel = node.labelNode;
-       dojo.addClass(node.labelNode, 'privtreeselected');
+       tree.lastFocused = node;
        updateNodeLabels(nodename);
        setLoading2(250);
-       /*if(dojo.byId('activeNodeAdd'))
-               dojo.byId('activeNodeAdd').value = nodeid;
-       if(dojo.byId('activeNodeDel'))
-               dojo.byId('activeNodeDel').value = nodeid;*/
        dojo.cookie('VCLACTIVENODE', nodeid, {expires: 365, path: '/', domain: 
cookiedomain});
        var obj = dojo.byId('nodecont');
        var data = {continuation: obj.value,
@@ -66,6 +75,23 @@ function nodeSelect(node) {
        RPCwrapper(data, generalPrivCB, 0);
 }
 
+function mouseDown(evt) {
+       dragging = 1;
+       dragnode.dragid = dragnode.hoverid;
+       dragnode.startX = mouseX;
+       dragnode.startY = mouseY;
+}
+
+function mouseRelease(evt) {
+       if(dragging == 0)
+               return;
+       dragging = 0;
+       if(mouseX == dragnode.startX && mouseY == dragnode.startY)
+               return;
+       if(nodedropdata[dragnode.dragid] == 0 || nodedropdata[dragnode.hoverid] 
== 0 || mouseontree == 0)
+               setSelected(dijit.byId('privtree').lastFocused.item.name[0]);
+}
+
 function updateNodeLabels(nodename) {
        dojo.byId('addPaneNodeName').innerHTML = 'Node: <strong>' + nodename + 
'</strong>';
        dojo.byId('addGroupPaneNodeName').innerHTML = 'Node: <strong>' + 
nodename + '</strong>';
@@ -94,27 +120,19 @@ function showPrivPane(name) {
 function focusFirstNode(id) {
        var tree = dijit.byId('privtree');
        if(tree._itemNodesMap && tree._itemNodesMap[id]) {
-               var children = tree.rootNode.getChildren();
-               var fc = children[0];
-               if(fc !== tree._itemNodesMap[id][0]) {
-                       fc.setSelected(false);
-               }
-               tree._onNodeFocus(tree._itemNodesMap[id][0]);
-               tree.lastLabel = tree._itemNodesMap[id][0].labelNode;
-               dojo.addClass(tree._itemNodesMap[id][0].labelNode, 
'privtreeselected');
+               setSelected(id);
+               updateNodeLabels(tree._itemNodesMap[id][0].label);
                tree.lastFocused = tree._itemNodesMap[id][0];
-               var nodename = tree.lastLabel.innerHTML;
-               updateNodeLabels(nodename);
        }
        else if(tree._itemNodesMap &&
                tree.model.root.children &&
                tree._itemNodesMap[tree.model.root.children[0].name[0]]) {
                var pnodeids = new Array();
-               var node = tree.store._itemsByIdentity[id];
+               var node = tree.model.store._itemsByIdentity[id];
                while(node._RRM) {
                        for(var pid in node._RRM) {
                                pnodeids.push(pid);
-                               node = tree.store._itemsByIdentity[pid];
+                               node = tree.model.store._itemsByIdentity[pid];
                        }
                }
                var pid;
@@ -144,21 +162,40 @@ function submitAddChildNode() {
        RPCwrapper(data, generalPrivCB, 0);
 }
 
-function addChildNode(name, id) {
+function addChildNode(name, id, parentid) {
        var tree = dijit.byId('privtree');
-       var store = tree.store;
+       var store = tree.model.store;
        // determine selected node
        var parentnode = tree.lastFocused.item;
        // add new node to selected node
-       var nodedata = {name: id, display: name};
+       var nodedata = {name: id, display: name, parent: parentid};
        var parentdata = {parent: parentnode, attribute: 'children'};
        var newnode = store.newItem(nodedata, parentdata);
+       var parentitem = tree._itemNodesMap[parentid][0].item;
+       positionNode(newnode, parentitem);
 
        // hide addNodePane
        dojo.byId('childNodeName').value = '';
        dojo.byId('addChildNodeStatus').innerHTML = '';
        setTimeout(function() {dijit.byId('addNodePane').hide();}, 100);
-       
+       nodedropdata[id] = 1;
+}
+
+function positionNode(node, parent) {
+       var index = 0;
+       var decr = 0;
+       for(var i = 0; i < parent.children.length; i++) {
+               if(node.display[0].localeCompare(parent.children[i].display[0]) 
== 0)
+                       decr = 1;
+               if(node.display[0].localeCompare(parent.children[i].display[0]) 
== -1)
+                       break;
+       }
+       index = i;
+       if(decr)
+               index--;
+       nomove = 1;
+       nodemodel.pasteItem(node, parent, parent, 0, index);
+       nomove = 0;
 }
 
 function deleteNodes() {
@@ -171,10 +208,8 @@ function deleteNodes() {
 
 function setSelectedPrivNode(nodeid) {
        var tree = dijit.byId('privtree');
-       var store = tree.store;
-       dojo.addClass(tree._itemNodesMap[nodeid][0].labelNode, 
'privtreeselected');
-       tree.lastLabel = tree._itemNodesMap[nodeid][0].labelNode;
-       tree.lastLabel.focus();
+       var store = tree.model.store;
+       setSelected(nodeid);
        tree.lastFocused = tree._itemNodesMap[nodeid][0];
        updateNodeLabels(tree.lastFocused.label);
        setLoading2(250);
@@ -190,7 +225,12 @@ function removeNodesFromTree(idlist) {
        var tree = dijit.byId('privtree');
        var ids = idlist.split(',');
        for(var i in ids) {
-               tree.store.fetchItemByIdentity({
+               if(typeof(moveitem) !== 'undefined' &&
+                  ids[i] == moveitem.oldparentid) {
+                       moveitem = undefined;
+                       dijit.byId('revertMoveNodeBtn').set('disabled', true);
+               }
+               tree.model.store.fetchItemByIdentity({
                        identity: ids[i],
                        onItem: removeNodesFromTreeCB
                });
@@ -200,18 +240,22 @@ function removeNodesFromTree(idlist) {
 function removeNodesFromTreeCB(item, request) {
        if(item) {
                var tree = dijit.byId('privtree');
-               tree.store.deleteItem(item);
+               nomove = 1;
+               tree.model.store.deleteItem(item);
+               nomove = 0;
        }
 }
 
 function renameNode() {
        var tree = dijit.byId('privtree');
        var contid = dojo.byId('renamecont').value;
-       var newname = dojo.byId('newNodeName').value;
+       dijit.byId('submitRenameNodeBtn').focus();
+       var newname = dijit.byId('newNodeName').value;
        var curname = tree.lastFocused.item.display[0];
        if(! newname.length)
                return;
-       if(newname == tree.lastFocused.item.display[0]) {
+       if(newname == curname) {
+               dijit.byId('newNodeName').focus();
                dojo.byId('renameNodeStatus').innerHTML = 'You must enter a 
different name';
                return;
        }
@@ -236,13 +280,18 @@ function renameNodeCB(data, ioArgs) {
        var newname = data.items.newname;
        var nodeid = data.items.node;
        var tree = dijit.byId('privtree');
-       tree.store.fetchItemByIdentity({
+       tree.model.store.fetchItemByIdentity({
                identity: nodeid,
                onItem: function(item, request) {
                        var tree = dijit.byId('privtree');
-                       var store = tree.store;
+                       var store = tree.model.store;
+                       nomove = 1;
                        store.setValue(item, 'display', newname);
-                       dojo.addClass(tree.lastLabel, 'privtreeselected');
+                       nomove = 0;
+                       setTimeout(function() {
+                               var parentitem = 
tree._itemNodesMap[item.parent[0]][0].item;
+                               positionNode(item, parentitem);
+                       }, 500);
                }
        });
        clearRenameBox();
@@ -594,3 +643,212 @@ function hideUserGroupPrivs() {
        dijit.byId('usergroupcopyprivsbtn').setAttribute('disabled', true);
        dijit.byId('usergroupsaveprivsbtn').setAttribute('disabled', true);
 }
+
+function moveNode(node) {
+       if(nomove)
+               return;
+       if(saveMoveNode == 0) {
+               saveMoveNode = node.name[0];
+               return;
+       }
+       var node1 = saveMoveNode;
+       var node2 = node.name[0];
+       if(node1 == node2) {
+               var tree = dijit.byId('privtree');
+               var nodeitem = tree._itemNodesMap[dragnode.dragid][0].item;
+               var parentid = nodeitem.parent[0];
+               var parentitem = tree._itemNodesMap[parentid][0].item;
+               positionNode(nodeitem, parentitem);
+               if(nodeitem != tree.lastFocused.item)
+                       setSelected(tree.lastFocused.item.name[0]);
+               saveMoveNode = 0;
+               return;
+       }
+
+       var tree = dijit.byId('privtree');
+       var moveid = dragnode.dragid;
+       var oldparentid = tree._itemNodesMap[dragnode.dragid][0].item.parent[0];
+       if(oldparentid == node1)
+               var newparentid = node2;
+       else
+               var newparentid = node1;
+
+       var nodeitem = tree._itemNodesMap[moveid][0].item;
+       var parentitem = tree._itemNodesMap[newparentid][0].item;
+       positionNode(nodeitem, parentitem);
+
+       var movename = nodeitem.display[0];
+       for(var i = 0; i < parentitem.children.length; i++) {
+               var child = parentitem.children[i];
+               if(movename == child.display[0] && newparentid == 
child.parent[0]) {
+                       var oldparentitem = 
tree._itemNodesMap[oldparentid][0].item;
+                       nomove = 1;
+                       nodemodel.pasteItem(nodeitem, parentitem, 
oldparentitem, 0, 0);
+                       positionNode(nodeitem, oldparentitem);
+                       nomove = 0;
+                       alert('Another node with the same name and parent as 
the node being moved already exists.');
+                       saveMoveNode = 0;
+                       return;
+               }
+       }
+
+       var data = {continuation: dojo.byId('movenodecont').value,
+                   moveid: moveid,
+                   oldparentid: oldparentid,
+                   newparentid: newparentid}
+       RPCwrapper(data, moveNodeCB, 1);
+       saveMoveNode = 0;
+}
+
+function moveNodeCB(data, ioArgs) {
+       moveitem = new moveData();
+       moveitem.moveid = data.items.moveid;
+       moveitem.oldparentid = data.items.oldparentid;
+       moveitem.newparentid = data.items.newparentid;
+       if(data.items.status == 'invaliddata') {
+               alert('Error: invalid data submitted');
+               revertNodeMove();
+               return;
+       }
+       else if(data.items.status == 'noaccess') {
+               alert('You do not have access to move the selected nodes to the 
selected location.');
+               revertNodeMove();
+               return;
+       }
+       else if(data.items.status == 'collision') {
+               alert('Another node with the same name and parent as the node 
being moved already exists.');
+               revertNodeMove();
+               return;
+       }
+       else if(data.items.status == 'nochange') {
+               return;
+       }
+       dojo.byId('revertmovenodecont').value = data.items.revertcont;
+       dojo.byId('moveNodeName').innerHTML = data.items.movename;
+       dojo.byId('moveNodeOldParentName').innerHTML = data.items.oldparent;
+       dojo.byId('moveNodeNewParentName').innerHTML = data.items.newparent;
+       dojo.byId('movenodesubmitcont').value = data.items.continuation;
+       dijit.byId('moveDialog').show();
+}
+
+function submitMoveNode() {
+       var data = {continuation: dojo.byId('movenodesubmitcont').value};
+       RPCwrapper(data, submitMoveNodeCB, 1);
+}
+
+function submitMoveNodeCB(data, ioArgs) {
+       dijit.byId('moveDialog').hide();
+       dijit.byId('revertMoveNodeBtn').set('disabled', false);
+       nodestore.fetchItemByIdentity({
+               identity: moveitem.moveid,
+               onItem: function(item, request) {
+                       nomove = 1;
+                       dijit.byId('privtree').model.store.setValue(item, 
'parent', data.items.newparentid);
+                       nomove = 0;
+                       var selnode = dijit.byId('privtree').selectedNode;
+                       if(selnode.item == item) {
+                               nodeSelect(selnode);
+                       }
+               }
+       });
+       refreshNodeDropData();
+}
+
+function submitRevertMoveNode() {
+       var data = {continuation: dojo.byId('revertmovenodecont').value};
+       RPCwrapper(data, submitRevertMoveNodeCB, 1);
+}
+
+function submitRevertMoveNodeCB(data, ioArgs) {
+       revertNodeMove();
+       dijit.byId('revertMoveNodeDlg').hide();
+       dijit.byId('revertMoveNodeBtn').set('disabled', true);
+       moveitem = undefined;
+       refreshNodeDropData();
+}
+
+function revertNodeMove() {
+       nodestore.fetchItemByIdentity({
+               identity: moveitem.moveid,
+               onItem: function(item, request) {
+                       revertNodeMoveCB('movenode', item);
+               }
+       });
+       nodestore.fetchItemByIdentity({
+               identity: moveitem.oldparentid,
+               onItem: function(item, request) {
+                       revertNodeMoveCB('oldparent', item);
+               }
+       });
+       nodestore.fetchItemByIdentity({
+               identity: moveitem.newparentid,
+               onItem: function(item, request) {
+                       revertNodeMoveCB('newparent', item);
+               }
+       });
+}
+
+function revertNodeMoveCB(type, item) {
+       if(type == 'movenode') {
+               moveitem.moveobj = item;
+               moveitem.moveset = 1;
+       }
+       else if(type == 'oldparent') {
+               moveitem.oldparentobj = item;
+               moveitem.oldparentset = 1;
+       }
+       else if(type == 'newparent') {
+               moveitem.newparentobj = item;
+               moveitem.newparentset = 1;
+       }
+       if(moveitem.oldparentset == 1 &&
+          moveitem.newparentset == 1 &&
+          moveitem.moveset == 1) {
+               var index = -1;
+               if('children' in moveitem.oldparentobj) {
+                       for(var i = 0; i < 
moveitem.oldparentobj.children.length; i++) {
+                               
if(moveitem.moveobj.display[0].localeCompare(moveitem.oldparentobj.children[i].display[0])
 == -1) {
+                                       break;
+                               }
+                       }
+               }
+               index = i;
+               nomove = 1;
+               nodemodel.pasteItem(moveitem.moveobj, moveitem.newparentobj, 
moveitem.oldparentobj, 0, index);
+               dijit.byId('privtree').model.store.setValue(moveitem.moveobj, 
'parent', moveitem.oldparentobj.name[0]);
+               
nodeSelect(dijit.byId('privtree')._itemNodesMap[moveitem.moveobj.name[0]][0]);
+               nomove = 0;
+       }
+}
+
+function setSelected(nodeid) {
+       var tree = dijit.byId('privtree');
+       var selpath = [];
+       while(typeof(tree._itemNodesMap[nodeid]) !== 'undefined') {
+               selpath.unshift(tree._itemNodesMap[nodeid][0].item);
+               nodeid = tree._itemNodesMap[nodeid][0].item.parent[0];
+       }
+       selpath.unshift(tree.model.root);
+       tree.attr('path', selpath);
+}
+
+function checkCanMove(tree, domnodes) {
+       var node = dijit.getEnclosingWidget(domnodes[0]);
+       var nodeid = node.item.name[0];
+       if(nodedropdata[nodeid] == 0)
+               return false;
+       return true;
+}
+
+function checkNodeDrop(domnode, tree, position) {
+       var node = dijit.getEnclosingWidget(domnode);
+       var nodeid = node.item.name[0];
+       if(nodedropdata[nodeid] == 0)
+               return false;
+       return true;
+}
+
+function refreshNodeDropData() {
+       var data = {continuation: dojo.byId('refreshnodedropdatacont').value};
+       RPCwrapper(data, generalPrivCB, 0);
+}



Reply via email to