[richfaces-svn-commits] JBoss Rich Faces SVN: r11758 - in trunk/ui/tree/src: main/java/org/richfaces/component and 4 other directories.

richfaces-svn-commits at lists.jboss.org richfaces-svn-commits at lists.jboss.org
Sun Dec 14 13:07:10 EST 2008


Author: nbelaevski
Date: 2008-12-14 13:07:10 -0500 (Sun, 14 Dec 2008)
New Revision: 11758

Removed:
   trunk/ui/tree/src/test/java/org/richfaces/renderkit/TreeRowKeyComparatorTest.java
Modified:
   trunk/ui/tree/src/main/config/component/tree.xml
   trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java
   trunk/ui/tree/src/main/java/org/richfaces/component/events/TreeEvents.java
   trunk/ui/tree/src/main/java/org/richfaces/renderkit/TreeRendererBase.java
   trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree-item.js
   trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree-selection.js
   trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree.js
Log:
https://jira.jboss.org/jira/browse/RF-4196

Modified: trunk/ui/tree/src/main/config/component/tree.xml
===================================================================
--- trunk/ui/tree/src/main/config/component/tree.xml	2008-12-14 18:03:41 UTC (rev 11757)
+++ trunk/ui/tree/src/main/config/component/tree.xml	2008-12-14 18:07:10 UTC (rev 11758)
@@ -303,6 +303,10 @@
 			<defaultvalue>""</defaultvalue>
 		</property>
 		
+		<property>
+			<name>ajaxNodeKeys</name>
+		</property>
+		
 		<property hidden="true">
 			<name>rowKeyConverter</name>
 		</property>

Modified: trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java	2008-12-14 18:03:41 UTC (rev 11757)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/UITree.java	2008-12-14 18:07:10 UTC (rev 11758)
@@ -24,11 +24,14 @@
 import java.io.IOException;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import javax.el.ValueExpression;
 import javax.faces.application.Application;
 import javax.faces.component.NamingContainer;
 import javax.faces.component.UIComponent;
@@ -58,12 +61,15 @@
 import org.richfaces.component.state.events.ExpandAllCommandEvent;
 import org.richfaces.component.state.events.ExpandNodeCommandEvent;
 import org.richfaces.component.state.events.TreeStateCommandEvent;
+import org.richfaces.event.AjaxExpandedEvent;
 import org.richfaces.event.DragListener;
 import org.richfaces.event.DropListener;
 import org.richfaces.event.NodeExpandedEvent;
 import org.richfaces.event.NodeExpandedListener;
 import org.richfaces.event.NodeSelectedEvent;
 import org.richfaces.event.NodeSelectedListener;
+import org.richfaces.event.TreeAjaxEvent;
+import org.richfaces.event.TreeAjaxEventType;
 import org.richfaces.event.TreeListenerEventsProducer;
 import org.richfaces.model.AbstractTreeDataModel;
 import org.richfaces.model.CacheableTreeDataModel;
@@ -117,6 +123,10 @@
 
 	private UITreeNode defaultFacet;
 	
+	private Set<Object> ajaxNodeKeys = null;
+	
+	private Set<Object> nodeRequestKeys = null;
+	
 	/**
 	 * Name of EL variable for the tree node.
 	 * This reference is needed to let this parent class
@@ -587,7 +597,7 @@
 
 		// fire node events
 		TreeEvents.invokeListenerBindings(this, event, getFacesContext());
-
+		
 		if (event instanceof AjaxEvent) {
 			FacesContext facesContext = getFacesContext();
 			AjaxRendererUtils.addRegionsFromComponent(this, facesContext);
@@ -941,10 +951,11 @@
 
 
 	public Object saveState(FacesContext faces) {
-		Object[] state = new Object[3];
+		Object[] state = new Object[4];
 		state[0] = super.saveState(faces);
 		state[1] = saveAttachedState(faces, defaultFacet);
 		state[2] = getTreeNodeVar();
+		state[3] = ajaxNodeKeys;
 
 		return state;
 	}
@@ -962,6 +973,7 @@
 			defaultFacet.setParent(this);
 		}
 		setTreeNodeVar((String) state[2]);
+		ajaxNodeKeys = (Set<Object>) state[3];
 	}
 	
 	public String getResolvedDragIndicator(FacesContext facesContext) {
@@ -1191,6 +1203,120 @@
 		TreeState treeState = (TreeState) getComponentState();
 		treeState.transferQueuedNodes((TreeRowKey) getRowKey());
 	}
-}
 
+	/**
+	 * @param o
+	 * @since 3.3.0
+	 */
+	public void addNodeRequestKey(Object o) {
+		if (o == null) {
+			throw new IllegalArgumentException();
+		}
+		
+		if (nodeRequestKeys == null) {
+			nodeRequestKeys = new HashSet<Object>();
+		}
+		
+		nodeRequestKeys.add(o);
+	}
+	
+	/**
+	 * @since 3.3.0
+	 */
+	public void clearNodeRequestKeysSet() {
+		if (nodeRequestKeys != null) {
+			nodeRequestKeys.clear();
+		}
+	}
+	
+	/**
+	 * @param o
+	 * @return
+	 * @since 3.3.0
+	 */
+	public boolean containsNodeRequestKey(Object o) {
+		return nodeRequestKeys != null && nodeRequestKeys.contains(o);
+	}
+	
+	/**
+	 * @param o
+	 * @since 3.3.0
+	 */
+	public void removeNodeRequestKey(Object o) {
+		if (nodeRequestKeys != null) {
+			nodeRequestKeys.remove(o);
+		}
+	}
+	
+	/**
+	 * @return
+	 * @since 3.3.0
+	 */
+	public Set<Object> getNodeRequestKeys() {
+		return nodeRequestKeys;
+	}
+	
+	/**
+	 * @return
+	 * @since 3.3.0
+	 */
+	public Set<Object> getAjaxNodeKeys() {
+		Set<Object> keys = null;
+		if (this.ajaxNodeKeys != null) {
+			keys = this.ajaxNodeKeys;
+		} else {
+			ValueExpression ve = this.getValueExpression("ajaxNodeKeys");
+			if (ve != null) {
+				keys = (Set<Object>) ve.getValue(getFacesContext().getELContext());
+			}
+		}
+		
+		return keys;
+	}
 
+	/**
+	 * @param keys
+	 * @since 3.3.0
+	 */
+	public void setAjaxNodeKeys(Set<Object> keys) {
+		this.ajaxNodeKeys = keys;
+	}
+	
+	/**
+	 * @return
+	 * @since 3.3.0
+	 */
+	public Set<Object> getAllAjaxNodeKeys() {
+		HashSet<Object> result = null;
+		
+		Set<Object> ajaxNodeKeys = getAjaxNodeKeys();
+		if (ajaxNodeKeys != null) {
+			result = new HashSet<Object>(ajaxNodeKeys);
+		}
+		
+		Set<Object> nodeRequestKeys = getNodeRequestKeys();
+		if (nodeRequestKeys != null) {
+			if (result != null) {
+				result.addAll(nodeRequestKeys);
+			} else {
+				result = new HashSet<Object>(nodeRequestKeys);
+			}
+		}
+		
+		return result;
+	}
+	
+	@Override
+	protected void addAjaxKeyEvent(FacesEvent event) {
+		if (event instanceof TreeAjaxEvent) {
+			TreeAjaxEvent treeAjaxEvent = (TreeAjaxEvent) event;
+			if (TreeAjaxEventType.EXPANSION.equals(treeAjaxEvent.getEventType())) {
+				addRequestKey(getRowKey());
+			} else {
+				super.addAjaxKeyEvent(event);
+			}
+		} else {
+			super.addAjaxKeyEvent(event);
+		}
+	}
+}
\ No newline at end of file

Modified: trunk/ui/tree/src/main/java/org/richfaces/component/events/TreeEvents.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/component/events/TreeEvents.java	2008-12-14 18:03:41 UTC (rev 11757)
+++ trunk/ui/tree/src/main/java/org/richfaces/component/events/TreeEvents.java	2008-12-14 18:07:10 UTC (rev 11758)
@@ -21,18 +21,20 @@
 
 package org.richfaces.component.events;
 
+import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.el.MethodBinding;
 import javax.faces.event.AbortProcessingException;
 import javax.faces.event.FacesEvent;
 
-import org.ajax4jsf.event.AjaxEvent;
 import org.richfaces.event.AjaxExpandedEvent;
 import org.richfaces.event.AjaxSelectedEvent;
 import org.richfaces.event.DragEvent;
 import org.richfaces.event.DropEvent;
 import org.richfaces.event.NodeExpandedEvent;
 import org.richfaces.event.NodeSelectedEvent;
+import org.richfaces.event.TreeAjaxEvent;
+import org.richfaces.event.TreeAjaxEventType;
 import org.richfaces.event.TreeListenerEventsProducer;
 
 /**
@@ -52,15 +54,16 @@
 			throws AbortProcessingException {
 		MethodBinding binding = null;
 
+		UIComponent component = event.getComponent();
 		if (event instanceof NodeExpandedEvent) {
 			binding = eventsProducer.getChangeExpandListener();
 			if (event instanceof AjaxExpandedEvent) {
-				new AjaxEvent(event.getComponent()).queue();
+				new TreeAjaxEvent(component, TreeAjaxEventType.EXPANSION).queue();
 			}
 		} else if (event instanceof AjaxSelectedEvent) {
 			if (eventsProducer.hasAjaxSubmitSelection()) {
 				binding = eventsProducer.getNodeSelectListener();
-				new AjaxEvent(event.getComponent()).queue();
+				new TreeAjaxEvent(component, TreeAjaxEventType.SELECTION).queue();
 			}
 		} else if (event instanceof NodeSelectedEvent) {
 			binding = eventsProducer.getNodeSelectListener();

Modified: trunk/ui/tree/src/main/java/org/richfaces/renderkit/TreeRendererBase.java
===================================================================
--- trunk/ui/tree/src/main/java/org/richfaces/renderkit/TreeRendererBase.java	2008-12-14 18:03:41 UTC (rev 11757)
+++ trunk/ui/tree/src/main/java/org/richfaces/renderkit/TreeRendererBase.java	2008-12-14 18:07:10 UTC (rev 11758)
@@ -56,47 +56,32 @@
 
 public abstract class TreeRendererBase extends CompositeRenderer {
 
-	protected final static Comparator treeRowKeyComparator = new Comparator() {
+	protected static final class RowKeyHolder {
 
-		public int compare(Object key1, Object key2) {
-			TreeRowKey treeRowKey1 = (TreeRowKey) key1;
-			TreeRowKey treeRowKey2 = (TreeRowKey) key2;
+		private TreeRowKey<Object> rowKey;
+		
+		private boolean nodeKey;
+		
+		public RowKeyHolder(TreeRowKey<Object> rowKey, boolean nodeKey) {
+			super();
+			this.rowKey = rowKey;
+			this.nodeKey = nodeKey;
+		}
+		
+		public boolean isNodeKey() {
+			return nodeKey;
+		}
+		
+		public TreeRowKey<Object> getRowKey() {
+			return rowKey;
+		}
 
-			if (treeRowKey1 == null) {
-				if (treeRowKey2 == null) {
-					return 0;
-				} else {
-					return -1;
-				}
-			} else {
-				if (treeRowKey2 == null) {
-					return 1;
-				}
-			}
-
-			Iterator iterator1 = treeRowKey1.iterator();
-			Iterator iterator2 = treeRowKey2.iterator();
-
-			while (iterator1.hasNext() && iterator2.hasNext()) {
-				String id1 = iterator1.next().toString();
-				String id2 = iterator2.next().toString();
-
-				int cr = id1.compareTo(id2);
-				if (cr != 0) {
-					return cr;
-				}
-			}
-
-			if (iterator1.hasNext()) {
-				return 1;
-			} else if (iterator2.hasNext()) {
-				return -1;
-			} else {
-				return 0;
-			}
+		@Override
+		public String toString() {
+			return this.getClass().getSimpleName() + "[" + rowKey + "]";
 		}
 	};
-
+	
 	private final class RendererDataModelEventNavigator extends
 	TreeDataModelEventNavigator {
 		private final FacesContext context;
@@ -365,6 +350,38 @@
 		NSUtils.writeNameSpace(context, component);
 	}
 
+	private List<RowKeyHolder> getKeyHoldersList(Set subTreeKeys, 
+			Set nodeKeys, String treePath) {
+		
+		if (subTreeKeys != null && subTreeKeys.contains(null)) {
+			List<RowKeyHolder> list = new ArrayList<RowKeyHolder>(1);
+			list.add(new RowKeyHolder(null, false));
+			return list;
+		}
+		
+		List<RowKeyHolder> list = new ArrayList<RowKeyHolder>((subTreeKeys == null ? 0 : subTreeKeys.size()) + 
+				(nodeKeys == null ? 0 : nodeKeys.size()));
+		
+		if (subTreeKeys != null) {
+			for (Object subTreeKey : subTreeKeys) {
+				list.add(new RowKeyHolder((TreeRowKey<Object>) subTreeKey, false));
+			}
+		}
+
+		if (nodeKeys != null) {
+			for (Object nodeKey : nodeKeys) {
+				TreeRowKey<Object> treeRowKey = (TreeRowKey<Object>) nodeKey;
+				if (treeRowKey != null && treeRowKey.depth() != 0) {
+					list.add(new RowKeyHolder(treeRowKey, true));
+				} else {
+					log.warn("Top node of the [" + treePath + "] tree cannot be re-rendered without subnodes");
+				}
+			}
+		}
+		
+		return list;
+	}
+	
 	public void encodeAjaxChildren(FacesContext context, UIComponent component,
 			String path, Set ids, Set renderedAreas) throws IOException {
 		super.encodeAjaxChildren(context, component, path, ids, renderedAreas);
@@ -389,68 +406,88 @@
 				writeNamespace(context, component);
 
 				List encodedAreaIds = new ArrayList();
-
+				
 				try {
-					Set ajaxKeys = tree.getAllAjaxKeys(); 
-					if (ajaxKeys != null) {
-						List sortedKeys = new ArrayList(ajaxKeys.size());
-						sortedKeys.addAll(ajaxKeys);
-						Collections.sort(sortedKeys, treeRowKeyComparator);
-						Iterator ajaxKeysItr = sortedKeys.iterator();
-						TreeRowKey lastKey = null;
-						boolean nullRoot = false;
+					List<RowKeyHolder> keyHoldersList = getKeyHoldersList(
+						tree.getAllAjaxKeys(), 
+						tree.getAllAjaxNodeKeys(),
+						id);
 
-						while (!nullRoot && ajaxKeysItr.hasNext()) {
-							TreeRowKey key = (TreeRowKey) ajaxKeysItr.next();
+					Collections.sort(keyHoldersList, new Comparator<RowKeyHolder>() {
 
-							if (lastKey == null) {
-								lastKey = key;
-							} else {
-								if (!lastKey.isSubKey(key)) {
-									lastKey = key;
-								} else {
-									//skip nodes that's parent nodes have been rendered
-									continue;
-								}
-							}
+						public int compare(RowKeyHolder o1, RowKeyHolder o2) {
+							int d1 = o1.rowKey == null ? 0 : o1.rowKey.depth();
+							int d2 = o2.rowKey == null ? 0 : o2.rowKey.depth();
 
-							if (key == null || key.depth() == 0) {
-								nullRoot = true;
-								key = null;
+							return d1 < d2 ? -1 : (d2 > d1 ? 1 : 0);
+						}
+
+					});
+
+					List<RowKeyHolder> holders = new ArrayList<RowKeyHolder>();
+					for (RowKeyHolder holder : keyHoldersList) {
+						boolean isSubKey = false;
+
+						for (RowKeyHolder rowKeyHolder : holders) {
+							if (rowKeyHolder.rowKey == null || 
+									rowKeyHolder.rowKey.isSubKey(holder.rowKey)) {
+
+								isSubKey = true;
+								break;
 							}
+						}
 
-							tree.setRowKey(context, key);
+						if (!isSubKey) {
+							holders.add(holder);
+						}
+					}
 
-							if (key == null || tree.isRowAvailable()) {
-								String treeClientId;
-								if (key == null) {
-									treeClientId = tree.getClientId(context);
-								} else {
-									treeClientId = tree.getNodeFacet().getClientId(context);
-								}
+					Iterator<RowKeyHolder> ajaxKeysItr = holders.iterator();
+					while (ajaxKeysItr.hasNext()) {
+						RowKeyHolder keyHolder = ajaxKeysItr.next();
+						TreeRowKey key = keyHolder.getRowKey();
 
-								String treeChildrenId = treeClientId + NamingContainer.SEPARATOR_CHAR + "childs";
-								
-								writeContent(context, tree, key);
-								encodeScripts = true;
-								renderedAreas.add(treeClientId);
-								encodedAreaIds.add(treeClientId);
+						if (key != null && key.depth() == 0) {
+							key = null;
+						}
 
-								renderedAreas.add(treeChildrenId);
-								//encodedAreaIds.add(id+":childs");
+						tree.setRowKey(context, key);
+
+						if (key == null || tree.isRowAvailable()) {
+							String treeClientId;
+							if (key == null) {
+								treeClientId = tree.getClientId(context);
 							} else {
-								String cid = tree.getClientId(context);
-								String message = MessageFormat.format(
-										"Failed to re-render tree node: {0} due to model data unavailability! " +
-										"Maybe parent node should be re-rendered instead?", 
-										new Object[] { cid });
-								
-								ExternalContext externalContext = context.getExternalContext();
-								externalContext.log(message);
+								treeClientId = tree.getNodeFacet().getClientId(context);
 							}
+
+							encodeScripts = true;
+							
+							//should be added before children id
+							renderedAreas.add(treeClientId);
+
+							if (keyHolder.isNodeKey()) {
+								writeContent(context, tree, key, false);
+							} else {
+								writeContent(context, tree, key, true);
+								String treeChildrenId = treeClientId + NamingContainer.SEPARATOR_CHAR + "childs";
+								renderedAreas.add(treeChildrenId);
+							}
+
+							//add node to set of nodes refreshed by script
+							encodedAreaIds.add(treeClientId);
+						} else {
+							String cid = tree.getClientId(context);
+							String message = MessageFormat.format(
+									"Failed to re-render tree node: {0} due to model data unavailability! " +
+									"Maybe parent node should be re-rendered instead?", 
+									new Object[] { cid });
+
+							ExternalContext externalContext = context.getExternalContext();
+							externalContext.log(message);
 						}
-						//ajaxKeys.clear();
 					}
+					//ajaxKeys.clear();
 				} catch (Exception e) {
 					throw new FacesException(e);
 				} finally {
@@ -461,13 +498,9 @@
 						context.getExternalContext().log(e.getMessage(), e);
 					}
 				}
+
 				if (encodeScripts) {
 					writeScript(context, tree, encodedAreaIds, renderedAreas);
-
-					String inputId = encodeSelectionStateInput(context, tree);
-					if (inputId != null) {
-						renderedAreas.add(inputId);
-					}
 				}
 
 				responseWriter.endElement("div");
@@ -482,7 +515,7 @@
 		}
 	}
 
-	public String encodeSelectionStateInput(FacesContext context, UITree tree) throws IOException {
+	protected String getSelectionValue(FacesContext context, UITree tree) {
 		String result = "";
 		TreeState treeState = (TreeState) tree.getComponentState();
 		TreeRowKey selectedNodeKey = treeState.getSelectedNode();
@@ -501,7 +534,11 @@
 				}
 			}
 		}
-
+		
+		return result;
+	}
+	
+	public String encodeSelectionStateInput(FacesContext context, UITree tree) throws IOException {
 		ResponseWriter writer = context.getResponseWriter();
 		writer.startElement("input", tree);
 		writer.writeAttribute("type", "hidden", null);
@@ -509,7 +546,7 @@
 		writer.writeAttribute("id", selectionHolderInputId, null);
 		writer.writeAttribute("name", selectionHolderInputId, null);
 
-		writer.writeAttribute("value", result, null);
+		writer.writeAttribute("value", ScriptUtils.toScript(getSelectionValue(context, tree)), null);
 		writer.endElement("input");
 
 		return selectionHolderInputId;
@@ -555,8 +592,10 @@
 
 		writer.writeText(varName + ".getNodeElements(" + 
 				ScriptUtils.toScript(encodedAreaIds) + ");", null);
-
-
+		
+		writer.writeText(varName + ".updateSelection(" + 
+				ScriptUtils.toScript(getSelectionValue(context, tree)) + ");", null);
+		
 		writer.endElement("script");
 		writer.endElement("div");
 
@@ -570,16 +609,16 @@
 	public void encodeChildren(FacesContext context, UIComponent component)
 	throws IOException {
 
-		writeContent(context, (UITree) component, null);
+		writeContent(context, (UITree) component, null, true);
 	}
 
 	public void writeContent(final FacesContext context, final UITree input)
 	throws IOException {
-		writeContent(context, input, null);
+		writeContent(context, input, null, true);
 	}
 
 	public void writeContent(final FacesContext context, final UITree input,
-			TreeRowKey key) throws IOException {
+			TreeRowKey key, final boolean withSubnodes) throws IOException {
 		// simple flag can be used here because
 		// we cannot jump more than one level down until next node
 		// when rendering
@@ -600,7 +639,7 @@
 			TreeRange treeRange = new TreeRange() {
 
 				public boolean processChildren(TreeRowKey rowKey) {
-					return stateRange.processChildren(rowKey);
+					return withSubnodes ? stateRange.processChildren(rowKey) : false;
 				}
 
 				public boolean processNode(TreeRowKey rowKey) {
@@ -683,4 +722,4 @@
 	public void setHasChildren(boolean hasChildren) {
 		this.hasChildren = hasChildren;
 	}
-}
\ No newline at end of file
+}

Modified: trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree-item.js
===================================================================
--- trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree-item.js	2008-12-14 18:03:41 UTC (rev 11757)
+++ trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree-item.js	2008-12-14 18:07:10 UTC (rev 11758)
@@ -1,13 +1,19 @@
-Tree.Item = Class.create();
+Tree.Item = Class.create(Richfaces.TreeComposite);
 
-Tree.Item.findComponent = function(elt) {
-	while (elt && (!elt.tagName || elt.tagName.toLowerCase() != 'table')) {
-		elt = elt.parentNode;
+Tree.Item.findComponent = function(elt, axisFunction) {
+	var component;
+	
+	while (elt && !((component = elt.object) instanceof Tree.Item)) {
+		if (axisFunction) {
+			elt = axisFunction(elt);
+		} else {
+			elt = elt.parentNode;
+		}
 	}
 	
-	return elt.object;
+	return component;
 };
- 
+
 Tree.Item.fireCollapsionEvent = function(elt) {
 	return Tree.Item.findComponent(elt).fireCollapsionEvent();
 };
@@ -16,13 +22,57 @@
 	return Tree.Item.findComponent(elt).fireExpansionEvent();
 };
 
+Tree.Item.createItemForNode = function() {
+	var getComponentIndex = function(node) {
+		var idx = 0;
+		var n = node;
+	
+		while (n) {
+			if (n.object instanceof Tree.Item) {
+				idx++;
+			}
+			
+			n = n.previousSibling;
+			
+		};
+		
+		return idx;
+	};
+	
+	var findParentComponent = function(node) {
+		var n = node.parentNode;
+		if (n) {
+			n = Richfaces.previous(n);
+		}
+		
+		if (n) {
+			return n.object;
+		}
+	};
+	
+	return function(node, tree) {
+		var replacedNode = $(node);
+		
+		var pNode = findParentComponent(replacedNode) || tree;
+		var idx = getComponentIndex(replacedNode);
+		
+		var item = new Tree.Item(replacedNode, tree, true);
+		
+		pNode.addChild(item, idx);
 
-Tree.Item.prototype = {
-	initialize: function(id, tree, parent, ajaxUpdate) {
-		this.parent = parent;
+		return item;
+	};
+}();
+
+Tree.Item.addMethods({
+	initialize: function($super, id, tree, ajaxUpdate) {
+		$super();
+		
 		this.tree = tree;
 		this.elements = {};
 		
+		this["rich:destructor"] = "destroy";
+		
 		var element;
 		
 		if (typeof id == 'string') {
@@ -33,9 +83,11 @@
 			this.id = element.id;
 		}
 		
+		element.component = this;
 		element.object = this;
 		
 		var rows = element.rows;
+		this.elements.itemElement = element;
 		this.elements.mainRow = rows[0];
 		
 		var sibling = element.nextSibling;
@@ -50,8 +102,24 @@
 		var iconId = this.id + Tree.ID_DEVIDER + Tree.ID_ICON;
 		var textId = this.id + Tree.ID_DEVIDER + Tree.ID_TEXT;
 		
-		this.getElements(element, ajaxUpdate);
+		var childsTd = Richfaces.next(element);
+		this.createSubNodes(childsTd);
 
+		if (ajaxUpdate && this.tree.showConnectingLines) {
+			var cell = element.rows[0].cells[0];
+			if (cell.style && cell.style.removeExpression) {
+				cell.style.backgroundImage = cell.currentStyle.backgroundImage;
+				cell.style.removeExpression('backgroundImage');
+			}
+	
+			if (childsTd) {
+				if (childsTd.style && childsTd.style.removeExpression) {
+					childsTd.style.backgroundImage = childsTd.currentStyle.backgroundImage;
+					childsTd.style.removeExpression('backgroundImage');
+				}
+			}
+		}
+
 		var handles = null;
 		var cells = this.elements.mainRow.cells;
 		if ("NETSCAPE" == RichFaces.navigatorType()) {
@@ -105,7 +173,7 @@
 		if	(dropOpts) {
 			this.enableDropzoneCursors(dropOpts.acceptCursor, dropOpts.rejectCursor);
 		}
-		 
+
 		this.observeEvents();
 		
 		this.previousTextClassNames = null;
@@ -114,15 +182,18 @@
 	},
 
 	destroy: function() {
+		this.elements = undefined;
+		
+		//TODO remove check
+		if (this.parent) {
+			this.parent.removeChild(this);
+		}
+		
+		this.clearChildren();
+		
 		if (this == this.tree.selectionManager.activeItem) {
 			this.tree.selectionManager.activeItem = null;
 		}
-		
-		for (var i = 0; i < this.childs.length; i++) {
-			this.childs[i].destroy();
-		}
-		
-		this.childs = null;
 	},
 
 	observeEvents: function() {
@@ -136,7 +207,7 @@
 			Event.observe(this.elements.iconElement, "mouseout", this.eventMouseOut);
 			Event.observe(this.elements.iconElement, "mouseover", this.eventMouseOver);
 			if (this.onContextMenu) {
-				this.elements.iconElement.oncontextmenu = this.onContextMenu;
+				Event.observe(this.elements.iconElement, "contextmenu", this.onContextMenu);
 			}			
 		}
 
@@ -146,11 +217,11 @@
 			Event.observe(this.elements.textElement, "mouseout", this.eventMouseOut);
 			Event.observe(this.elements.textElement, "mouseover", this.eventMouseOver);
 			if (this.onContextMenu) {
-				this.elements.textElement.oncontextmenu = this.onContextMenu;
+				Event.observe(this.elements.textElement, "contextmenu", this.onContextMenu);
 			}			
 		}
 
-		if (this.tree.switchType=="client" && this.childs.length > 0) {
+		if (this.tree.switchType=="client" && this.hasChilds()) {
 			this.eventCollapsionClick = this.toggleCollapsion.bindAsEventListener(this);
 			
 			var handleElt = this.tree.toggleOnClick ? this.elements.mainRow : this.elements.handle;
@@ -158,50 +229,24 @@
 		}
 	},
 
-	getElements: function(element, ajaxUpdate) {
-		this.childs = [];
-
-		var childsTd = element.nextSibling;
-		
-		if (ajaxUpdate && this.tree.showConnectingLines) {
-			var cell = element.rows[0].cells[0];
-			if (cell.style && cell.style.removeExpression) {
-				cell.style.backgroundImage = cell.currentStyle.backgroundImage;
-				cell.style.removeExpression('backgroundImage');
-			}
-	
-			if (childsTd) {
-				if (childsTd.style && childsTd.style.removeExpression) {
-					childsTd.style.backgroundImage = childsTd.currentStyle.backgroundImage;
-					childsTd.style.removeExpression('backgroundImage');
-				}
-			}
-		}
-
-		if (childsTd) {
-			var child = childsTd.firstChild;
+	createSubNodes: function(childrenTd) {
+		if (childrenTd) {
+			var child = childrenTd.firstChild;
 			while ( child != null )
 			{
                 if (child.nodeType == 1 && child.tagName.toLowerCase() == "table") {
-                    this.addChild(new Tree.Item(child, this.tree, this));
+                	if (child.object instanceof Tree.Item) {
+                    	var item = child.object;
+                		this.addChild(item);
+                	} else {
+                		this.addChild(new Tree.Item(child, this.tree));
+                	}
                 }
                 child = child.nextSibling;
             }
-            /*
-            for (var i = 0; i < childsTd.childNodes.length; i++) {
-				var child = childsTd.childNodes[i];
-				if (child.nodeType == 1 && child.tagName.toLowerCase() == "table") {
-					this.addChild(new Tree.Item(child.id, this.tree, this));
-				}
-			}
-			*/
 		}
 	},
 
-	addChild: function(child) {
-		this.childs.push(child);
-	},
-
 	fireExpansionEvent: function() {
 		var props = new Object();
 		props[Richfaces.TreeExpandEvent] = true;
@@ -455,32 +500,26 @@
 		}
 	},
 
-	next: function() {
-		var children = this.parent.childs;
+	_nextForAxis: function(axisFunction) {
+		var item;
 		
-		for (var i = 0; i < children.length - 1; i++) {
-			if (children[i] == this) {
-				return children[i + 1];
-			}
+		if (this.elements && this.elements.itemElement) {
+			item = Tree.Item.findComponent(axisFunction(this.elements.itemElement), axisFunction);
 		}
 		
-		return this;
+		return item || this;
 	},
+	
+	next: function() {
+		return this._nextForAxis(Richfaces.next);
+	},
 
 	previous: function() {
-		var children = this.parent.childs;
-
-		for (var i = 1; i < children.length; i++) {
-			if (children[i] == this) {
-				return children[i - 1];
-			}
-		}
-
-		return this;
+		return this._nextForAxis(Richfaces.previous);
 	},
 
 	hasChilds: function() {
-		return this.childs.length > 0;
+		return this.childs && this.childs.length > 0;
 	},
 	
 	getElement: function() {
@@ -490,4 +529,5 @@
 	isLeaf: function() {
 		return !this.elements.handle;		
 	}
-}
+	
+});

Modified: trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree-selection.js
===================================================================
--- trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree-selection.js	2008-12-14 18:03:41 UTC (rev 11757)
+++ trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree-selection.js	2008-12-14 18:07:10 UTC (rev 11758)
@@ -175,9 +175,7 @@
 	getPreviousItemForSelection: function(item) {
 		var prev = item.previous();
 		if (prev == item) {
-			if (prev.parent == this.tree) {
-				prev = item;
-			} else {
+			if (item.parent != this.tree && item.parent) {
 				prev = item.parent;
 			}
 		} else if (!prev.isCollapsed() && prev.hasChilds()) {

Modified: trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree.js
===================================================================
--- trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree.js	2008-12-14 18:03:41 UTC (rev 11757)
+++ trunk/ui/tree/src/main/resources/org/richfaces/renderkit/html/scripts/tree.js	2008-12-14 18:07:10 UTC (rev 11758)
@@ -2,7 +2,51 @@
 Richfaces.TreeExpandEvent = "Richfaces.TreeExpandEvent";
 Richfaces.TreeCollapseEvent = "Richfaces.TreeCollapseEvent";
 
-Tree = Class.create();
+Richfaces.TreeComposite = Class.create({
+
+	parent: null,
+	
+	initialize: function() {
+		this.childs = [];
+	},
+	
+	removeChild: function(child) {
+		if (this.childs.length) {
+			var idx = this.childs.indexOf(child);
+			if (idx != -1) {
+				var removedChildren = this.childs.splice(idx, 1);
+				if (removedChildren) {
+					for (var i = 0; i < removedChildren.length; i++) {
+						removedChildren[i].parent = undefined;
+					}
+				}
+			}
+		}
+	},
+	
+	addChild: function(child, idx) {
+		var start;
+		if (typeof idx != 'undefined') {
+			start = idx;
+		} else {
+			start = this.childs.length;
+		}
+		
+		this.childs.splice(start, 0, child);
+		child.parent = this;
+	},
+	
+	clearChildren: function() {
+		for (var i = 0; i < this.childs.length; i++) {
+			this.childs[i].parent = undefined;
+		}
+		
+		this.childs = [];
+	}
+	
+});
+
+Tree = Class.create(Richfaces.TreeComposite);
 Tree.ID_DEVIDER = ":";
 Tree.ID_CONTENT = "content";
 Tree.ID_CHILDS_ROW = "childs";
@@ -19,8 +63,9 @@
 Tree.CLASS_ITEM_COLLAPSED = "dr-tree-h-ic-line-clp";
 Tree.CLASS_AJAX_SELECTED_LISTENER_FLAG = "ajax_selected_listener_flag";
 
-Tree.prototype = {
-	initialize: function(id, input, switchType, events, onAjaxSelect, toggleOnClick, showConnectingLines) {
+Tree.addMethods({
+	initialize: function($super, id, input, switchType, events, onAjaxSelect, toggleOnClick, showConnectingLines) {
+		$super();
 		this.childs = [];
 		this.elements = {};
 
@@ -122,69 +167,41 @@
 			Tree.ID_DEVIDER + Tree.ID_CHILDS_ROW/* + Tree.ID_DEVIDER + Tree.ID_CHILDS_TD*/);
 
 		if (this.elements.contentTd) {
-            for(var child = this.elements.contentTd.firstChild; child != null; child = child.nextSibling ) {
+			for(var child = this.elements.contentTd.firstChild; child != null; child = child.nextSibling ) {
                 if (child.nodeType == 1 && child.tagName.toLowerCase() == "table") {
-                    this.addChild(new Tree.Item(child, this, this, ajaxUpdate));
+                    this.addChild(new Tree.Item(child, this, ajaxUpdate));
                 }
             }
             /*
             for (var i = 0; i < this.elements.contentTd.childNodes.length; i++) {
 				var child = this.elements.contentTd.childNodes[i];
 				if (child.nodeType == 1 && child.tagName.toLowerCase() == "table") {
-					this.addChild(new Tree.Item(child.id, this, this, this.childs.length, this.switchType, this.toggleOnClick));
+					this.addChild(new Tree.Item(child.id, this, this.childs.length, this.switchType, this.toggleOnClick));
 				}
 			}
 			*/
 		}
 	},
 
-	addChild: function(child) {
-		this.childs.push(child);
-	},
-
 	getNodeElements: function(nodeIds) {
 		if (nodeIds) {
 			for (var i = 0; i < nodeIds.length; i++ ) {
 				var nodeId = nodeIds[i];
-				if (nodeId != this.id) {
-					this._getNodeElements(this, nodeId, nodeId.substring(0, nodeId.lastIndexOf('::')));
+				if (nodeId == this.id) {
+					this.clearChildren();	
+					this.getElements(true);
 				} else {
-					for (var i = 0; i < this.childs.length; i++) {
-						var child = this.childs[i];
-						child.destroy();
-					}
-					
-					this.childs = [];	
-					this.getElements(true);
+					Tree.Item.createItemForNode(nodeId, this);
 				}
 			}
-
-			//input holding selection has been refreshed
-			this.input = $(this.inputId);
-			this.selectionManager.restoreSelection();
 		}
 	},
-
-	_getNodeElements: function(node, nodeId, sNodeId) {
-		for (var i = 0; i < node.childs.length; i++) {
-			var child = node.childs[i];
-			var cid = child.id;
-			
-			if (cid == nodeId) {
-				child.destroy();
-				node.childs[i] = new Tree.Item(cid, this, child.parent, true);
-				break;
-			} else {
-				var scid = cid.substring(0, cid.lastIndexOf('::'));
-				if (sNodeId.substr(0, scid.length) == scid && sNodeId.charAt(scid.length) == ':') {
-					
-					this._getNodeElements(child, nodeId, sNodeId);
-					break;
-				}
-			}
-		}
+	
+	updateSelection: function(selectedNode) {
+		this.input.value = selectedNode;
+		this.selectionManager.restoreSelection();
 	},
-
+	
 	showNode: function(itemNode) {
 		var node = itemNode;
 		var offsetTopItem = 0;
@@ -206,6 +223,4 @@
 	getElement: function() {
 		return $(this.id);
 	}
-}
-
-
+});
\ No newline at end of file

Deleted: trunk/ui/tree/src/test/java/org/richfaces/renderkit/TreeRowKeyComparatorTest.java
===================================================================
--- trunk/ui/tree/src/test/java/org/richfaces/renderkit/TreeRowKeyComparatorTest.java	2008-12-14 18:03:41 UTC (rev 11757)
+++ trunk/ui/tree/src/test/java/org/richfaces/renderkit/TreeRowKeyComparatorTest.java	2008-12-14 18:07:10 UTC (rev 11758)
@@ -1,101 +0,0 @@
-/**
- * License Agreement.
- *
- *  JBoss RichFaces - Ajax4jsf Component Library
- *
- * Copyright (C) 2007  Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
- */
-
-package org.richfaces.renderkit;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-
-import org.richfaces.model.ListRowKey;
-
-import junit.framework.TestCase;
-
-/**
- * 
- * <br /><br />
- * 
- * Created 22.08.2007
- * @author Nick Belaevski
- * @since 3.1
- */
-
-public class TreeRowKeyComparatorTest extends TestCase {
-
-	/* (non-Javadoc)
-	 * @see junit.framework.TestCase#setUp()
-	 */
-	protected void setUp() throws Exception {
-		super.setUp();
-	}
-
-	/* (non-Javadoc)
-	 * @see junit.framework.TestCase#tearDown()
-	 */
-	protected void tearDown() throws Exception {
-		super.tearDown();
-	}
-
-	public void testComparator() throws Exception {
-		Comparator comparator = TreeRendererBase.treeRowKeyComparator;
-	
-		ListRowKey emptyKey = new ListRowKey();
-		ListRowKey key = new ListRowKey(new Integer(23));
-		ListRowKey eqkey = new ListRowKey(new Integer(23));
-		ListRowKey supKey = new ListRowKey(new ListRowKey(new Integer(23)), new Integer(34));
-	
-		ListRowKey predLongKey = new ListRowKey(new ListRowKey(new ListRowKey(new Integer(22)), new Integer(0)), new Integer(8));
-		ListRowKey predKey = new ListRowKey(new Integer(22));
-		ListRowKey predSupKey = new ListRowKey(new ListRowKey(new Integer(22)), new Integer(34));
-		ListRowKey succKey = new ListRowKey(new ListRowKey(new Integer(25)), new Integer(34));
-		ListRowKey succSupKey = new ListRowKey(new ListRowKey(new ListRowKey(new Integer(25)), new Integer(34)), new Integer(2));
-	
-		ArrayList list = new ArrayList();
-		list.add(eqkey);
-		list.add(succSupKey);
-		list.add(succKey);
-		list.add(predSupKey);
-		list.add(predKey);
-		list.add(supKey);
-		list.add(key);
-		list.add(null);
-		list.add(emptyKey);
-		list.add(null);
-		list.add(predLongKey);
-		
-		Collections.sort(list, comparator);
-		
-		Iterator iterator = list.iterator();
-		assertNull(iterator.next());
-		assertNull(iterator.next());
-		assertEquals(emptyKey, iterator.next());
-		assertEquals(predKey, iterator.next());
-		assertEquals(predLongKey, iterator.next());
-		assertEquals(predSupKey, iterator.next());
-		assertEquals(eqkey, iterator.next());
-		assertEquals(key, iterator.next());
-		assertEquals(supKey, iterator.next());
-		assertEquals(succKey, iterator.next());
-		assertEquals(succSupKey, iterator.next());
-	
-	}
-}




More information about the richfaces-svn-commits mailing list