Author: drobiazko Date: Fri Jul 1 20:24:03 2011 New Revision: 1142070 URL: http://svn.apache.org/viewvc?rev=1142070&view=rev Log: TAP5-1562: Made tree leafs selectable
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeExpansionModel.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeExpansionModel.java tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java?rev=1142070&r1=1142069&r2=1142070&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/EventConstants.java Fri Jul 1 20:24:03 2011 @@ -209,4 +209,20 @@ public class EventConstants */ public static final String PREALLOCATE_FORM_CONTROL_NAMES = "preallocateFormControlNames"; + /** + * Event triggered by the {@link org.apache.tapestry5.corelib.components.Tree} + * component when a leaf node is selected. + * + * @since 5.3.1 + */ + public static final String NODE_SELECTED = "nodeSelected"; + + /** + * Event triggered by the {@link org.apache.tapestry5.corelib.components.Tree} + * component when a leaf node is unselected. + * + * @since 5.3.1 + */ + public static final String NODE_UNSELECTED = "nodeUnselected"; + } Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java?rev=1142070&r1=1142069&r2=1142070&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java Fri Jul 1 20:24:03 2011 @@ -14,21 +14,17 @@ package org.apache.tapestry5.corelib.components; +import java.util.Arrays; import java.util.List; -import org.apache.tapestry5.BindingConstants; -import org.apache.tapestry5.Block; -import org.apache.tapestry5.ComponentResources; -import org.apache.tapestry5.Link; -import org.apache.tapestry5.MarkupWriter; -import org.apache.tapestry5.annotations.Environmental; -import org.apache.tapestry5.annotations.Parameter; -import org.apache.tapestry5.annotations.Persist; -import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.*; +import org.apache.tapestry5.annotations.*; +import org.apache.tapestry5.corelib.internal.InternalFormSupport; import org.apache.tapestry5.dom.Element; import org.apache.tapestry5.func.F; import org.apache.tapestry5.func.Flow; import org.apache.tapestry5.func.Worker; +import org.apache.tapestry5.internal.util.CaptureResultCallback; import org.apache.tapestry5.ioc.annotations.Inject; import org.apache.tapestry5.json.JSONObject; import org.apache.tapestry5.runtime.RenderCommand; @@ -49,6 +45,7 @@ import org.apache.tapestry5.tree.TreeNod */ @SuppressWarnings( { "rawtypes", "unchecked", "unused" }) +@Events({EventConstants.NODE_SELECTED, EventConstants.NODE_UNSELECTED}) public class Tree { /** @@ -162,30 +159,34 @@ public class Tree boolean hasChildren = !node.isLeaf() && node.getHasChildren(); boolean expanded = hasChildren && expansionModel.isExpanded(node); - if (hasChildren) - { - String clientId = jss.allocateClientId(resources); + String clientId = jss.allocateClientId(resources); - e.attribute("id", clientId); + JSONObject spec = new JSONObject("clientId", clientId); + e.attribute("id", clientId); + + if (hasChildren) + { Link expandChildren = resources.createEventLink("expandChildren", node.getId()); Link markExpanded = resources.createEventLink("markExpanded", node.getId()); Link markCollapsed = resources.createEventLink("markCollapsed", node.getId()); - JSONObject spec = new JSONObject("clientId", clientId, - - "expandChildrenURL", expandChildren.toString(), - - "markExpandedURL", markExpanded.toString(), - - "markCollapsedURL", markCollapsed.toString()); + spec.put("expandChildrenURL", expandChildren.toString()) + .put( "markExpandedURL", markExpanded.toString()) + .put("markCollapsedURL", markCollapsed.toString()); if (expanded) spec.put("expanded", true); + } + else + { + Link toggleLeaf = resources.createEventLink("toggleLeaf", node.getId()); - jss.addInitializerCall("treeNode", spec); + spec.put("toggleLeafURL", toggleLeaf.toString()); } + jss.addInitializerCall("treeNode", spec); + writer.end(); // span.tx-tree-icon // From here on in, we're pushing things onto the queue. Remember that @@ -263,6 +264,37 @@ public class Tree return new JSONObject(); } + Object onToggleLeaf(String nodeId) + { + TreeNode node = model.getById(nodeId); + + String event; + + if(expansionModel.isSelected(node)) + { + expansionModel.unselect(node); + + event = EventConstants.NODE_UNSELECTED; + } + else + { + expansionModel.select(node); + + event = EventConstants.NODE_SELECTED; + } + + CaptureResultCallback<Object> callback = CaptureResultCallback.create(); + + resources.triggerEvent(event, new Object [] { nodeId }, callback); + + final Object result = callback.getResult(); + + if(result != null) + return result; + + return new JSONObject(); + } + public TreeExpansionModel getDefaultTreeExpansionModel() { if (defaultTreeExpansionModel == null) Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeExpansionModel.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeExpansionModel.java?rev=1142070&r1=1142069&r2=1142070&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeExpansionModel.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeExpansionModel.java Fri Jul 1 20:24:03 2011 @@ -30,34 +30,73 @@ public class DefaultTreeExpansionModel<T { private final Set<String> expandedIds = CollectionFactory.newSet(); + private final Set<String> selectedIds = CollectionFactory.newSet(); + public boolean isExpanded(TreeNode<T> node) { - assert node != null; - - return expandedIds.contains(node.getId()); + return contains(expandedIds, node); } public void markExpanded(TreeNode<T> node) { + add(expandedIds, node); + } + + public void markCollapsed(TreeNode<T> node) + { + remove(expandedIds, node); + } + + public boolean isSelected(TreeNode<T> node) + { + return contains(selectedIds, node); + } + + public void select(TreeNode<T> node) + { + add(selectedIds, node); + } + + public void unselect(TreeNode<T> node) + { + remove(selectedIds, node); + } + + public void clear() + { + clearSet(expandedIds); + + clearSet(selectedIds); + } + + private void add(Set<String> ids, TreeNode<T> node) + { assert node != null; - if (expandedIds.add(node.getId())) + if (ids.add(node.getId())) markDirty(); } - public void markCollapsed(TreeNode<T> node) + private void remove(Set<String> ids, TreeNode<T> node) { assert node != null; - if (expandedIds.remove(node.getId())) + if (ids.remove(node.getId())) markDirty(); } - public void clear() + private boolean contains(Set<String> ids, TreeNode<T> node) + { + assert node != null; + + return ids.contains(node.getId()); + } + + private void clearSet(Set<String> set) { - if (!expandedIds.isEmpty()) + if (!set.isEmpty()) { - expandedIds.clear(); + set.clear(); markDirty(); } } Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeExpansionModel.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeExpansionModel.java?rev=1142070&r1=1142069&r2=1142070&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeExpansionModel.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeExpansionModel.java Fri Jul 1 20:24:03 2011 @@ -42,6 +42,12 @@ public interface TreeExpansionModel<T> /** Marks the node as collapsed (not expanded). */ void markCollapsed(TreeNode<T> node); + boolean isSelected(TreeNode<T> node); + + void select(TreeNode<T> node); + + void unselect(TreeNode<T> node); + /** Marks all nodes as collapsed. */ void clear(); } Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css?rev=1142070&r1=1142069&r2=1142070&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css Fri Jul 1 20:24:03 2011 @@ -51,6 +51,10 @@ SPAN.t-tree-icon.t-leaf-node { background-position: -32px -16px; } +SPAN.t-tree-label.t-selected-leaf-node-label { + font-weight: bold; +} + SPAN.t-tree-icon.t-empty-node { cursor: default; background-position: -32px 0px !important; Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js?rev=1142070&r1=1142069&r2=1142070&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js Fri Jul 1 20:24:03 2011 @@ -63,6 +63,8 @@ T5.extendInitializer(function() { function initializer(spec) { var loaded = spec.expanded; var expanded = spec.expanded; + var selected = false; + if (expanded) { $(spec.clientId).addClassName("t-tree-expanded") } @@ -95,16 +97,41 @@ T5.extendInitializer(function() { } + function toggleLeafHandler(reply) { + var response = reply.responseJSON; + + $(spec.clientId).update(""); + + Tapestry.loadScriptsInReply(response, function() { + loading = false; + loaded = true; + expanded = true; + selected = !selected; + }); + } + function doLoad() { if (loading) return; loading = true; - $(spec.clientId).addClassName("t-empty-node"); + if(spec.expandChildrenURL) + { + $(spec.clientId).addClassName("t-empty-node"); + } + else + { + $(spec.clientId).next("span.t-tree-label").addClassName("t-selected-leaf-node-label"); + } $(spec.clientId).update("<span class='t-ajax-wait'/>"); - Tapestry.ajaxRequest(spec.expandChildrenURL, successHandler); + var requestURL = spec.expandChildrenURL? spec.expandChildrenURL:spec.toggleLeafURL; + + var handler = spec.expandChildrenURL? successHandler: toggleLeafHandler; + + Tapestry.ajaxRequest(requestURL, handler); + } $(spec.clientId).observe("click", function(event) { @@ -117,6 +144,25 @@ T5.extendInitializer(function() { return; } + if(spec.toggleLeafURL) + { + var label = $(spec.clientId).next("span.t-tree-label"); + + if(selected) + { + label.removeClassName("t-selected-leaf-node-label"); + } + else + { + label.addClassName("t-selected-leaf-node-label"); + } + selected = !selected; + + Tapestry.ajaxRequest(spec.toggleLeafURL, {}); + + return; + } + // Children have been loaded, just a matter of toggling // between showing or hiding the children. Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy?rev=1142070&r1=1142069&r2=1142070&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy Fri Jul 1 20:24:03 2011 @@ -19,10 +19,6 @@ import org.testng.annotations.Test class TreeTests extends SeleniumTestCase { - /** - * Haven't figured out how to get Selenium to click the actual elements, never mine - * coordinate the wait for the Ajax. So far its just been manual testing. - */ @Test void basics() { @@ -32,20 +28,41 @@ class TreeTests extends SeleniumTestCase clickAndWait "link=clear expansions" - if (false) { - click "//span[@class='t-tree-icon'][2]" + //Click on Games + click "//div[@class='t-tree-container test-hook']/ul/li[2]/span[@class='t-tree-icon']" - sleep 100 + waitForCSSSelectedElementToAppear "span.t-tree-expanded" - click "//span[@class='t-tree-icon'][3]" + assertTextPresent "Board Games" - sleep 100 + //Click on Board Games + click "//div[@class='t-tree-container test-hook']/ul/li[2]/ul/li/span[@class='t-tree-icon']" - assertTextPresent "Agricola" + //Assert the leafs are displayed + waitForCondition "window.\$\$(\"span.t-leaf-node\").size() >= 5", "45000" - clickAndWait "link=Redraw" + clickAndWait "link=Redraw" - assertTextPresent "Agricola" - } + assertTextPresent "Settlers of Catan", "Agricola" + } + + @Test + void selectLeaf() { + + openBaseURL() + + clickAndWait "link=Tree Component Demo" + + clickAndWait "link=clear expansions" + + click "//span[@class='t-tree-icon']" + + waitForCSSSelectedElementToAppear "span.t-leaf-node" + + assertTextPresent "Oscar", "Gromit", "Max", "Roger", "Cooper" + + click "//span[@class='t-tree-icon t-leaf-node']" + + waitForCSSSelectedElementToAppear "span.t-selected-leaf-node-label" } }