Rewrite Tree: basic node expansion

Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/23a69ca7
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/23a69ca7
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/23a69ca7

Branch: refs/heads/5.4-js-rewrite
Commit: 23a69ca7b052669dd4f3c3fcb1fba14079679ad6
Parents: fa70aae
Author: Howard M. Lewis Ship <[email protected]>
Authored: Sun Nov 18 00:09:58 2012 +0000
Committer: Howard M. Lewis Ship <[email protected]>
Committed: Sun Nov 18 00:09:58 2012 +0000

----------------------------------------------------------------------
 .../coffeescript/META-INF/modules/core/tree.coffee |   72 +++++++++
 .../apache/tapestry5/corelib/components/Tree.java  |  118 +++++++++------
 .../apache/tapestry5/corelib/components/Tree.tml   |   16 +-
 3 files changed, 150 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/23a69ca7/tapestry-core/src/main/coffeescript/META-INF/modules/core/tree.coffee
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/coffeescript/META-INF/modules/core/tree.coffee 
b/tapestry-core/src/main/coffeescript/META-INF/modules/core/tree.coffee
new file mode 100644
index 0000000..9242165
--- /dev/null
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/tree.coffee
@@ -0,0 +1,72 @@
+# Copyright 2012 The Apache Software Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# ## core/tree
+#
+# Handlers to support to the core/Tree Tapestry component
+define ["core/dom", "core/ajax", "core/zone"],
+  (dom, ajax) ->
+
+    TREE = "[data-component-type=core/Tree]"
+    NODE_ID = "data-node-id"
+    SELECTOR = "#{TREE} [#{NODE_ID}]"
+
+    LOADING = "tree-children-loading"
+    LOADED = "tree-children-loaded"
+
+    loadChildren = (node) ->
+
+      # Ignore duplicate requests to load the children.
+
+      return if node.meta LOADING
+
+      container = node.findContainer TREE
+      url = container.attribute "data-tree-action-url"
+
+      node.meta LOADING, true
+
+      node.addClass "t-empty-node"
+      node.update "<span class='t-ajax-wait'/>"
+
+      ajax url,
+        parameters:
+          "t:action": "expand"
+          "t:nodeid": node.attribute NODE_ID
+        onsuccess: (reply) ->
+          node.update("").removeClass "t-empty-node"
+
+          label = node.findContainer("li").findFirst(".t-tree-label")
+
+          label.insertAfter reply.responseJSON.content
+
+          node.meta LOADING, false
+          node.meta LOADED, true
+
+    clickHandler = ->
+
+      # First case is dynamically loaded due to user action; second case
+      # is rendered with overall page due to server-side expansion model.
+      loaded = (this.meta LOADED) or (this.attribute "data-node-expanded")
+
+      if (not loaded) and (not this.hasClass "t-empty-node")
+        loadChildren this
+        return false
+
+      return false
+
+    dom.onDocument "click", SELECTOR, clickHandler
+
+
+    return null
+  

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/23a69ca7/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java
index fd639f4..4fd8ee8 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java
@@ -1,4 +1,4 @@
-// Copyright 2011 The Apache Software Foundation
+// Copyright 2011, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -38,15 +38,22 @@ import java.util.List;
  * <p/>
  * The Tree component uses special tricks to support recursive rendering of 
the Tree as necessary.
  *
- * @since 5.3
  * @tapestrydoc
+ * @since 5.3
  */
 @SuppressWarnings(
         {"rawtypes", "unchecked", "unused"})
 @Events({EventConstants.NODE_SELECTED, EventConstants.NODE_UNSELECTED})
+@Import(module = "core/tree")
 public class Tree
 {
     /**
+     * Name of query parameter that stores the node id of the node being 
operated on
+     * (expanded, collapsed, etc.).
+     */
+    private static final String NODE_ID = "t:nodeid";
+
+    /**
      * The model that drives the tree, determining top level nodes and making 
revealing the overall structure of the
      * tree.
      */
@@ -134,8 +141,10 @@ public class Tree
      * This is a mix of immediate rendering, and queuing up various Blocks and 
Render commands
      * to do the rest. May recursively render child nodes of the active node.
      *
-     * @param node   to render
-     * @param isLast if true, add "t-last" attribute to the LI element
+     * @param node
+     *         to render
+     * @param isLast
+     *         if true, add "t-last" attribute to the LI element
      * @return command to render the node
      */
     private RenderCommand toRenderCommand(final TreeNode node, final boolean 
isLast)
@@ -153,58 +162,31 @@ public class Tree
                 writer.element("li");
 
                 if (isLast)
+                {
                     writer.attributes("class", "t-last");
+                }
 
                 Element e = writer.element("span", "class", "t-tree-icon");
 
                 if (node.isLeaf())
+                {
                     e.addClassName("t-leaf-node");
-                else if (!node.getHasChildren())
+                } else if (!node.getHasChildren())
+                {
                     e.addClassName("t-empty-node");
+                }
 
                 boolean hasChildren = !node.isLeaf() && node.getHasChildren();
                 boolean expanded = hasChildren && 
expansionModel.isExpanded(node);
 
-                String clientId = jss.allocateClientId(resources);
-
-                JSONObject spec = new JSONObject("clientId", clientId);
-
-                e.attribute("id", clientId);
+                writer.attributes("data-node-id", node.getId());
 
-                spec.put("leaf", node.isLeaf());
-
-                if (hasChildren)
-                {
-                    Link expandChildren = 
resources.createEventLink("expandChildren", node.getId());
-                    Link markExpanded = 
resources.createEventLink("markExpanded", node.getId());
-                    Link markCollapsed = 
resources.createEventLink("markCollapsed", node.getId());
-
-                    spec.put("expandChildrenURL", expandChildren.toString())
-                            .put("markExpandedURL", markExpanded.toString())
-                            .put("markCollapsedURL", markCollapsed.toString());
-
-                    if (expanded)
-                        spec.put("expanded", true);
-                } else
+                if (expanded)
                 {
-                    if (selectionModel != null)
-                    {
-                        // May need to address this in the future; in other 
tree implementations I've constructed,
-                        // folders are selectable, and selections even 
propagate up and down the tree.
-
-                        Link selectLeaf = resources.createEventLink("select", 
node.getId());
-
-                        spec.put("selectURL", selectLeaf.toString());
-                        if (selectionModel.isSelected(node))
-                        {
-                            spec.put("selected", true);
-                        }
-                    }
+                    writer.attributes("data-node-expanded", true);
                 }
 
-                jss.addInitializerCall("treeNode", spec);
-
-                writer.end(); // span.tx-tree-icon
+                writer.end(); // span.t-tree-icon
 
                 // From here on in, we're pushing things onto the queue. 
Remember that
                 // execution order is reversed from order commands are pushed.
@@ -212,7 +194,6 @@ public class Tree
                 queue.push(RENDER_CLOSE_TAG); // li
 
                 if (expanded)
-
                 {
                     queue.push(new RenderNodes(node.getChildren()));
                 }
@@ -222,9 +203,7 @@ public class Tree
                 queue.push(RENDER_LABEL_SPAN);
 
             }
-        }
-
-                ;
+        };
     }
 
     /**
@@ -264,7 +243,43 @@ public class Tree
         return className == null ? "t-tree-container" : "t-tree-container " + 
className;
     }
 
-    Object onExpandChildren(String nodeId)
+    public Link getTreeActionLink()
+    {
+        return resources.createEventLink("treeAction");
+    }
+
+    Object onTreeAction(@RequestParameter(NODE_ID) String nodeId,
+                        @RequestParameter("t:action") String action)
+    {
+        if (action.equalsIgnoreCase("expand"))
+        {
+            return doExpandChildren(nodeId);
+        }
+
+        if (action.equalsIgnoreCase("markExpanded"))
+        {
+            return doMarkExpanded(nodeId);
+        }
+
+        if (action.equalsIgnoreCase("markCollapsed"))
+        {
+            return doMarkCollapsed(nodeId);
+        }
+
+        if (action.equalsIgnoreCase("selected"))
+        {
+            return doUpdateSelected(nodeId, true);
+        }
+
+        if (action.equalsIgnoreCase("deselect"))
+        {
+            return doUpdateSelected(nodeId, false);
+        }
+
+        throw new IllegalArgumentException(String.format("Unexpected action: 
'%s' for Tree component.", action));
+    }
+
+    Object doExpandChildren(String nodeId)
     {
         TreeNode container = model.getById(nodeId);
 
@@ -273,21 +288,22 @@ public class Tree
         return new RenderNodes(container.getChildren());
     }
 
-    Object onMarkExpanded(String nodeId)
+    Object doMarkExpanded(@RequestParameter(NODE_ID) String nodeId)
     {
         expansionModel.markExpanded(model.getById(nodeId));
 
         return new JSONObject();
     }
 
-    Object onMarkCollapsed(String nodeId)
+
+    Object doMarkCollapsed(@RequestParameter(NODE_ID) String nodeId)
     {
         expansionModel.markCollapsed(model.getById(nodeId));
 
         return new JSONObject();
     }
 
-    Object onSelect(String nodeId, @RequestParameter("t:selected") boolean 
selected)
+    Object doUpdateSelected(String nodeId, boolean selected)
     {
         TreeNode node = model.getById(nodeId);
 
@@ -312,7 +328,9 @@ public class Tree
         final Object result = callback.getResult();
 
         if (result != null)
+        {
             return result;
+        }
 
         return new JSONObject();
     }
@@ -320,7 +338,9 @@ public class Tree
     public TreeExpansionModel getDefaultTreeExpansionModel()
     {
         if (defaultTreeExpansionModel == null)
+        {
             defaultTreeExpansionModel = new DefaultTreeExpansionModel();
+        }
 
         return defaultTreeExpansionModel;
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/23a69ca7/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Tree.tml
----------------------------------------------------------------------
diff --git 
a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Tree.tml
 
b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Tree.tml
index e7cebc5..8be548a 100644
--- 
a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Tree.tml
+++ 
b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Tree.tml
@@ -1,11 +1,13 @@
-<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"; 
xmlns:p="tapestry:parameter">
+<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd";>
 
-  <div class="${containerClass}">
-    <t:delegate to="renderRootNodes"/>
-  </div>
+    <div class="${containerClass}"
+         data-component-type="core/Tree"
+         data-tree-action-url="${treeActionLink}">
+        <t:delegate to="renderRootNodes"/>
+    </div>
 
-  <t:block id="defaultRenderTreeNodeLabel">
-    ${node.label}
-  </t:block>
+    <t:block id="defaultRenderTreeNodeLabel">
+        ${node.label}
+    </t:block>
 
 </t:container>
\ No newline at end of file

Reply via email to