Author: nbelaevski
Date: 2010-10-31 09:42:28 -0400 (Sun, 31 Oct 2010)
New Revision: 19793
Added:
trunk/core/api/src/main/java/org/richfaces/component/MetaComponentProcessor.java
trunk/core/impl/src/main/java/org/richfaces/context/BaseExtendedVisitContext.java
trunk/core/impl/src/main/java/org/richfaces/context/ExecuteExtendedVisitContext.java
trunk/core/impl/src/main/java/org/richfaces/context/PartialViewExecuteVisitCallback.java
trunk/core/impl/src/main/java/org/richfaces/context/RenderExtendedVisitContext.java
Removed:
trunk/core/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java
Modified:
trunk/core/api/src/main/java/org/richfaces/renderkit/MetaComponentRenderer.java
trunk/core/impl/src/main/java/org/richfaces/context/ComponentIdResolver.java
trunk/core/impl/src/main/java/org/richfaces/context/ComponentMatcherNode.java
trunk/core/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.java
trunk/core/impl/src/main/java/org/richfaces/renderkit/util/CoreRendererUtils.java
trunk/core/impl/src/main/java/org/richfaces/resource/ResourceFactoryImpl.java
trunk/core/impl/src/main/resources/META-INF/resources/richfaces.js
trunk/core/impl/src/test/java/org/richfaces/context/AjaxTableComponentImpl.java
trunk/core/impl/src/test/java/org/richfaces/context/ExtendedPartialVisitContextTest.java
trunk/core/impl/src/test/resources/javascript/4_0_0.html
trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/TreeNodeParser.java
trunk/examples/iteration-demo/src/main/webapp/tree.xhtml
trunk/ui/common/ui/src/main/java/org/richfaces/component/UIDataAdaptor.java
trunk/ui/common/ui/src/main/java/org/richfaces/component/util/HtmlUtil.java
trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/AjaxEventOptions.java
trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/RendererBase.java
trunk/ui/input/ui/src/main/java/org/richfaces/renderkit/AutocompleteRendererBase.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/AbstractTableRenderer.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/DataGridRenderer.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/ExtendedDataTableRenderer.java
trunk/ui/output/ui/src/main/java/org/richfaces/renderkit/html/TooltipRenderer.java
Log:
https://jira.jboss.org/browse/RF-9315
Added: trunk/core/api/src/main/java/org/richfaces/component/MetaComponentProcessor.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/component/MetaComponentProcessor.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/component/MetaComponentProcessor.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -0,0 +1,34 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.component;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface MetaComponentProcessor {
+
+ public void processMetaComponent(FacesContext context, String metaComponentId);
+
+}
Modified: trunk/core/api/src/main/java/org/richfaces/renderkit/MetaComponentRenderer.java
===================================================================
---
trunk/core/api/src/main/java/org/richfaces/renderkit/MetaComponentRenderer.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/core/api/src/main/java/org/richfaces/renderkit/MetaComponentRenderer.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -35,4 +35,6 @@
public void encodeMetaComponent(FacesContext context, UIComponent component, String
metaComponentId)
throws IOException;
+ public void decodeMetaComponent(FacesContext context, UIComponent component, String
metaComponentId);
+
}
Copied: trunk/core/impl/src/main/java/org/richfaces/context/BaseExtendedVisitContext.java
(from rev 19768,
trunk/core/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java)
===================================================================
--- trunk/core/impl/src/main/java/org/richfaces/context/BaseExtendedVisitContext.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/context/BaseExtendedVisitContext.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -0,0 +1,507 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.context;
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UINamingContainer;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
+import javax.faces.component.visit.VisitHint;
+import javax.faces.component.visit.VisitResult;
+import javax.faces.context.FacesContext;
+
+import org.richfaces.component.MetaComponentResolver;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class BaseExtendedVisitContext extends ExtendedVisitContext {
+
+ static final String ANY_WILDCARD = "*";
+
+ private static final int SHORT_ID_IN_CLIENTID_SEGMENTS_NUMBER = 2;
+
+ private final class CollectionProxy extends AbstractCollection<String> {
+
+ private CollectionProxy() {
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return directNodesMap.isEmpty();
+ }
+
+ @Override
+ public int size() {
+ return directNodesMap.size();
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ return new IteratorProxy(directNodesMap.keySet().iterator());
+ }
+
+ @Override
+ public boolean add(String o) {
+ return addNode(o);
+ }
+ }
+ // Little proxy collection implementation. We proxy the id
+ // collection so that we can detect modifications and update
+ // our internal state when ids to visit are added or removed.
+
+ // Little proxy iterator implementation used by CollectionProxy
+ // so that we can catch removes.
+ private final class IteratorProxy implements Iterator<String> {
+
+ private Iterator<String> wrapped;
+
+ private String current = null;
+
+ private IteratorProxy(Iterator<String> wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ public boolean hasNext() {
+ return wrapped.hasNext();
+ }
+
+ public String next() {
+ current = wrapped.next();
+
+ return current;
+ }
+
+ public void remove() {
+ if (current != null) {
+ ComponentMatcherNode node = directNodesMap.get(current);
+ removeNode(node);
+
+ current = null;
+ }
+
+ wrapped.remove();
+ }
+ }
+
+ private interface NodeOperationCommand {
+
+ public ComponentMatcherNode getNextNode(ComponentMatcherNode currentNode, String
nodeId, boolean isPattern);
+
+ public boolean processLastNode(ComponentMatcherNode lastNode, String fullId);
+ }
+
+ private NodeOperationCommand addNodeOperation = new NodeOperationCommand() {
+
+ public boolean processLastNode(ComponentMatcherNode lastNode, String fullId) {
+ if (!directNodesMap.containsKey(fullId)) {
+ directNodesMap.put(fullId, lastNode);
+ lastNode.markAdded();
+
+ ComponentMatcherNode n = lastNode;
+ int addedSegmentsCount = 0;
+ while (n != null && addedSegmentsCount <
SHORT_ID_IN_CLIENTID_SEGMENTS_NUMBER) {
+ if (!n.isPatternNode() && !n.isMetaComponentNode()) {
+ String shortId = n.getSource();
+ if (shortId != null) {
+ addedSegmentsCount++;
+ //TODO filter meta component ids
+ shortIds.add(shortId);
+ }
+ }
+
+ n = n.getParentNode();
+ }
+
+ if (!lastNode.hasPatternNodeInChain()) {
+ lastNode.addSubtreeId(fullId);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public ComponentMatcherNode getNextNode(ComponentMatcherNode currentNode, String
nodeId, boolean isPattern) {
+ return currentNode.getOrCreateChild(nodeId, isPattern);
+ }
+ };
+
+ private NodeOperationCommand removeNodeOperation = new NodeOperationCommand() {
+
+ public boolean processLastNode(ComponentMatcherNode lastNode, String fullId) {
+ ComponentMatcherNode node = directNodesMap.remove(fullId);
+ if (node != null) {
+ if (!node.hasPatternNodeInChain()) {
+ node.removeSubtreeId(fullId);
+ }
+
+ removeNode(node);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public ComponentMatcherNode getNextNode(ComponentMatcherNode currentNode, String
nodeId, boolean isPattern) {
+ return currentNode.getChild(nodeId, isPattern);
+ }
+ };
+
+ private IdParser idParser;
+
+ // The client ids to visit
+ private Collection<String> clientIds;
+
+ private Collection<String> shortIds;
+
+ // Our visit hints
+ private Set<VisitHint> hints;
+
+ private ComponentMatcherNode rootNode;
+
+ private Map<String, ComponentMatcherNode> directNodesMap;
+
+ /**
+ * Creates a PartialVisitorContext instance with the specified hints.
+ *
+ * @param facesContext
+ * the FacesContext for the current request
+ * @param clientIds
+ * the client ids of the components to visit
+ * @param hints
+ * a the VisitHints for this visit
+ * @throws NullPointerException
+ * if {@code facesContext} is {@code null}
+ */
+ public BaseExtendedVisitContext(FacesContext facesContext, Collection<String>
clientIds, Set<VisitHint> hints,
+ ExtendedVisitContextMode contextMode) {
+
+ super(facesContext, contextMode);
+
+ // Initialize our various collections
+ initializeCollections(clientIds);
+
+ // Copy and store hints - ensure unmodifiable and non-empty
+ EnumSet<VisitHint> hintsEnumSet = ((hints == null) || (hints.isEmpty())) ?
EnumSet.noneOf(VisitHint.class)
+ : EnumSet.copyOf(hints);
+
+ this.hints = Collections.unmodifiableSet(hintsEnumSet);
+ }
+
+ private IdParser setupIdParser(String id) {
+ if (idParser == null) {
+ idParser = new
IdParser(UINamingContainer.getSeparatorChar(getFacesContext()),
+ MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR);
+ }
+
+ idParser.setId(id);
+
+ return idParser;
+ }
+
+ private ComponentMatcherNode findMatchingNode(String clientId) {
+ ComponentMatcherNode node = rootNode;
+
+ IdParser idParser = setupIdParser(clientId);
+
+ while (node != null && idParser.findNext()) {
+ String componentId = idParser.getComponentId();
+ String metadataComponentId = idParser.getMetadataComponentId();
+
+ if (metadataComponentId != null) {
+ node = node.getChild(componentId, false);
+ if (node != null) {
+ node = node.getChild(metadataComponentId, false);
+ }
+ } else {
+ node = node.getMatchedChild(componentId);
+ }
+ }
+
+ return node;
+ }
+
+ private ComponentMatcherNode findAddedNode(String clientId) {
+ ComponentMatcherNode node = findMatchingNode(clientId);
+
+ if (node != null && !node.isAdded()) {
+ node = null;
+ }
+
+ return node;
+ }
+
+ private void removeNode(ComponentMatcherNode nodeToRemove) {
+ nodeToRemove.markRemoved();
+
+ ComponentMatcherNode node = nodeToRemove;
+ while (node != null && !node.hasDirectChildren()) {
+ ComponentMatcherNode parentNode = node.getParentNode();
+ if (parentNode != null) {
+ parentNode.removeChild(node);
+ node = parentNode;
+ } else {
+ break;
+ }
+ }
+ }
+
+ private boolean invokeNodeOperation(NodeOperationCommand command,
ComponentMatcherNode currentNode,
+ IdTreeNode idTreeNode, StringBuilder sb) {
+
+ String componentId = idTreeNode.getComponentId();
+ String metadataComponentId = idTreeNode.getMetadataComponentId();
+
+ ComponentMatcherNode nextNode;
+
+ if (metadataComponentId != null) {
+ nextNode = command.getNextNode(currentNode, componentId, false);
+ if (nextNode != null) {
+ nextNode = command.getNextNode(nextNode, metadataComponentId, false);
+ nextNode.setMetaComponentNode(true);
+ }
+ } else {
+ boolean isPattern = ANY_WILDCARD.equals(componentId);
+ nextNode = command.getNextNode(currentNode, componentId, isPattern);
+ }
+
+ boolean result = false;
+
+ if (nextNode != null) {
+ final int bufferLength = sb.length();
+ if (bufferLength != 0) {
+ //TODO replace with constant
+ sb.append(':');
+ }
+ sb.append(componentId);
+ if (metadataComponentId != null) {
+ sb.append(metadataComponentId);
+ }
+
+ List<IdTreeNode> idTreeChildNodes = idTreeNode.getChildNodes();
+ if (idTreeChildNodes != null) {
+ final int newBufferLength = sb.length();
+
+ for (IdTreeNode idTreeChildNode : idTreeChildNodes) {
+ result |= invokeNodeOperation(command, nextNode, idTreeChildNode,
sb);
+
+ sb.setLength(newBufferLength);
+ }
+ } else {
+ result |= command.processLastNode(nextNode, sb.toString());
+ }
+
+ sb.setLength(bufferLength);
+ }
+
+ return result;
+ }
+
+ private boolean invokeRootNodeOperation(NodeOperationCommand command, IdTreeNode
idTreeNode) {
+ boolean result = false;
+
+ List<IdTreeNode> idTreeChildNodes = idTreeNode.getChildNodes();
+ if (idTreeChildNodes != null) {
+ StringBuilder sb = new StringBuilder();
+
+ for (IdTreeNode idTreeChildNode : idTreeChildNodes) {
+ result |= invokeNodeOperation(command, rootNode, idTreeChildNode, sb);
+ }
+ }
+
+ return result;
+ }
+
+ private boolean addNode(String patternId) {
+ IdTreeNode idTreeNode = new IdTreeNode();
+ idTreeNode.appendNodesFromParser(setupIdParser(patternId));
+
+ return invokeRootNodeOperation(addNodeOperation, idTreeNode);
+ }
+
+ private boolean removeNode(String patternId) {
+ IdTreeNode idTreeNode = new IdTreeNode();
+ idTreeNode.appendNodesFromParser(setupIdParser(patternId));
+
+ return invokeRootNodeOperation(removeNodeOperation, idTreeNode);
+ }
+
+ /**
+ * @see VisitContext#getHints VisitContext.getHints
+ */
+ @Override
+ public Set<VisitHint> getHints() {
+ return hints;
+ }
+
+ /**
+ * @see VisitContext#getIdsToVisit VisitContext.getIdsToVisit()
+ */
+ @Override
+ public Collection<String> getIdsToVisit() {
+
+ // We just return our clientIds collection. This is
+ // the modifiable (but proxied) collection of all of
+ // the client ids to visit.
+ return clientIds;
+ }
+
+ protected boolean hasImplicitSubtreeIdsToVisit(UIComponent component) {
+ return false;
+ }
+
+ /**
+ * @see VisitContext#getSubtreeIdsToVisit VisitContext.getSubtreeIdsToVisit()
+ */
+ @Override
+ public Collection<String> getSubtreeIdsToVisit(UIComponent component) {
+
+ // Make sure component is a NamingContainer
+ if (!(component instanceof NamingContainer)) {
+ throw new IllegalArgumentException("Component is not a NamingContainer:
" + component);
+ }
+
+ if (hasImplicitSubtreeIdsToVisit(component)) {
+ return VisitContext.ALL_IDS;
+ }
+
+ String clientId = buildExtendedClientId(component);
+
+ ComponentMatcherNode node = findMatchingNode(clientId);
+
+ Collection<String> result = null;
+
+
+ if (node != null) {
+ if (node.hasKidPatternNodes()) {
+ result = VisitContext.ALL_IDS;
+ } else {
+ Collection<String> subtreeIds = node.getSubtreeIds();
+ if (subtreeIds != null) {
+ result = Collections.unmodifiableCollection(subtreeIds);
+ } else {
+ //TODO nick - this code addresses the case of parent pattern nodes,
and can be optimized
+ if (node.hasDirectIdChildren()) {
+ result = VisitContext.ALL_IDS;
+ } else {
+ result = Collections.emptySet();
+ }
+ }
+ }
+ } else {
+ result = Collections.emptySet();
+ }
+
+ return result;
+ }
+
+ protected void addDirectSubtreeIdsToVisitForImplicitComponents(UIComponent component,
Set<String> result) {
+ }
+
+ public Collection<String>getDirectSubtreeIdsToVisit(UIComponent component) {
+ // Make sure component is a NamingContainer
+ if (!(component instanceof NamingContainer)) {
+ throw new IllegalArgumentException("Component is not a NamingContainer:
" + component);
+ }
+
+ String clientId = component.getClientId(getFacesContext());
+ ComponentMatcherNode node = findMatchingNode(clientId);
+
+ if (node != null && node.hasDirectPatternChildren()) {
+ return VisitContext.ALL_IDS;
+ }
+
+ Set<String> result = new HashSet<String>();
+ if (node != null && node.hasDirectIdChildren()) {
+ result.addAll(node.getIdChildren().keySet());
+ }
+
+ addDirectSubtreeIdsToVisitForImplicitComponents(component, result);
+
+ if (result != null && !result.isEmpty()) {
+ return Collections.unmodifiableCollection(result);
+ } else {
+ return Collections.emptySet();
+ }
+ }
+
+ protected VisitResult invokeVisitCallbackForImplicitComponent(UIComponent component,
VisitCallback callback) {
+ return VisitResult.ACCEPT;
+ }
+
+ protected boolean shouldCompleteOnEmptyIds() {
+ return true;
+ }
+
+ /**
+ * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
+ */
+ @Override
+ public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
{
+ if (shortIds.contains(component.getId())) {
+ String clientId = buildExtendedClientId(component);
+ ComponentMatcherNode node = findAddedNode(clientId);
+ if (node != null) {
+ VisitResult visitResult = callback.visit(this, component);
+
+ removeNode(clientId);
+
+ if (clientIds.isEmpty() && shouldCompleteOnEmptyIds()) {
+ return VisitResult.COMPLETE;
+ } else {
+ return visitResult;
+ }
+ }
+ }
+
+ return invokeVisitCallbackForImplicitComponent(component, callback);
+ }
+
+ // Called to initialize our various collections.
+ private void initializeCollections(Collection<String> clientIds) {
+ this.rootNode = new ComponentMatcherNode();
+ this.directNodesMap = new HashMap<String, ComponentMatcherNode>();
+ this.shortIds = new HashSet<String>();
+ this.clientIds = new CollectionProxy();
+ this.clientIds.addAll(clientIds);
+ }
+
+ public VisitContext createNamingContainerVisitContext(UIComponent component,
Collection<String> directIds) {
+ return new NamingContainerVisitContext(getFacesContext(), getVisitMode(),
component, directIds);
+ }
+}
Modified: trunk/core/impl/src/main/java/org/richfaces/context/ComponentIdResolver.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/context/ComponentIdResolver.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/core/impl/src/main/java/org/richfaces/context/ComponentIdResolver.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -168,7 +168,7 @@
continue;
}
- if (ExtendedPartialVisitContext.ANY_WILDCARD.equals(componentId)) {
+ if (BaseExtendedVisitContext.ANY_WILDCARD.equals(componentId)) {
continue;
}
Modified: trunk/core/impl/src/main/java/org/richfaces/context/ComponentMatcherNode.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/context/ComponentMatcherNode.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/core/impl/src/main/java/org/richfaces/context/ComponentMatcherNode.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -34,6 +34,8 @@
private boolean patternNode;
+ private boolean metaComponentNode = false;
+
private String source;
private boolean hasParentPatternNode;
@@ -332,4 +334,12 @@
public void setPatternNode(boolean patternNode) {
this.patternNode = patternNode;
}
+
+ public void setMetaComponentNode(boolean metaComponentNode) {
+ this.metaComponentNode = metaComponentNode;
+ }
+
+ public boolean isMetaComponentNode() {
+ return metaComponentNode;
+ }
}
Added:
trunk/core/impl/src/main/java/org/richfaces/context/ExecuteExtendedVisitContext.java
===================================================================
--- trunk/core/impl/src/main/java/org/richfaces/context/ExecuteExtendedVisitContext.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/context/ExecuteExtendedVisitContext.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -0,0 +1,47 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.context;
+
+import java.util.Collection;
+import java.util.Set;
+
+import javax.faces.component.visit.VisitHint;
+import javax.faces.context.FacesContext;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class ExecuteExtendedVisitContext extends BaseExtendedVisitContext {
+
+ /**
+ * @param facesContext
+ * @param clientIds
+ * @param hints
+ */
+ public ExecuteExtendedVisitContext(FacesContext facesContext,
Collection<String> clientIds, Set<VisitHint> hints) {
+
+ super(facesContext, clientIds, hints, ExtendedVisitContextMode.EXECUTE);
+ }
+
+
+}
Deleted:
trunk/core/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/core/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -1,532 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2010, Red Hat, Inc. and individual contributors
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.richfaces.context;
-
-import java.util.AbstractCollection;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.faces.component.NamingContainer;
-import javax.faces.component.UIComponent;
-import javax.faces.component.UINamingContainer;
-import javax.faces.component.visit.VisitCallback;
-import javax.faces.component.visit.VisitContext;
-import javax.faces.component.visit.VisitHint;
-import javax.faces.component.visit.VisitResult;
-import javax.faces.context.FacesContext;
-
-import org.ajax4jsf.component.AjaxOutput;
-import org.richfaces.component.MetaComponentResolver;
-
-/**
- * @author Nick Belaevski
- *
- */
-public class ExtendedPartialVisitContext extends ExtendedVisitContext {
-
- static final String ANY_WILDCARD = "*";
-
- private static final int SHORT_ID_IN_CLIENTID_SEGMENTS_NUMBER = 2;
-
- private final class CollectionProxy extends AbstractCollection<String> {
-
- private CollectionProxy() {
- }
-
- @Override
- public boolean isEmpty() {
- return directNodesMap.isEmpty();
- }
-
- @Override
- public int size() {
- return directNodesMap.size();
- }
-
- @Override
- public Iterator<String> iterator() {
- return new IteratorProxy(directNodesMap.keySet().iterator());
- }
-
- @Override
- public boolean add(String o) {
- return addNode(o);
- }
- }
- // Little proxy collection implementation. We proxy the id
- // collection so that we can detect modifications and update
- // our internal state when ids to visit are added or removed.
-
- // Little proxy iterator implementation used by CollectionProxy
- // so that we can catch removes.
- private final class IteratorProxy implements Iterator<String> {
-
- private Iterator<String> wrapped;
-
- private String current = null;
-
- private IteratorProxy(Iterator<String> wrapped) {
- this.wrapped = wrapped;
- }
-
- public boolean hasNext() {
- return wrapped.hasNext();
- }
-
- public String next() {
- current = wrapped.next();
-
- return current;
- }
-
- public void remove() {
- if (current != null) {
- ComponentMatcherNode node = directNodesMap.get(current);
- removeNode(node);
-
- current = null;
- }
-
- wrapped.remove();
- }
- }
-
- private interface NodeOperationCommand {
-
- public ComponentMatcherNode getNextNode(ComponentMatcherNode currentNode, String
nodeId, boolean isPattern);
-
- public boolean processLastNode(ComponentMatcherNode lastNode, String fullId);
- }
-
- private NodeOperationCommand addNodeOperation = new NodeOperationCommand() {
-
- public boolean processLastNode(ComponentMatcherNode lastNode, String fullId) {
- if (!directNodesMap.containsKey(fullId)) {
- directNodesMap.put(fullId, lastNode);
- lastNode.markAdded();
-
- ComponentMatcherNode n = lastNode;
- int addedSegmentsCount = 0;
- while (n != null && addedSegmentsCount <
SHORT_ID_IN_CLIENTID_SEGMENTS_NUMBER) {
- if (!n.isPatternNode()) {
- String shortId = n.getSource();
- if (shortId != null) {
- addedSegmentsCount++;
- //TODO filter meta component ids
- shortIds.add(shortId);
- }
- }
-
- n = n.getParentNode();
- }
-
- if (!lastNode.hasPatternNodeInChain()) {
- lastNode.addSubtreeId(fullId);
- }
-
- return true;
- }
-
- return false;
- }
-
- public ComponentMatcherNode getNextNode(ComponentMatcherNode currentNode, String
nodeId, boolean isPattern) {
- return currentNode.getOrCreateChild(nodeId, isPattern);
- }
- };
-
- private NodeOperationCommand removeNodeOperation = new NodeOperationCommand() {
-
- public boolean processLastNode(ComponentMatcherNode lastNode, String fullId) {
- ComponentMatcherNode node = directNodesMap.remove(fullId);
- if (node != null) {
- if (!node.hasPatternNodeInChain()) {
- node.removeSubtreeId(fullId);
- }
-
- removeNode(node);
-
- return true;
- }
-
- return false;
- }
-
- public ComponentMatcherNode getNextNode(ComponentMatcherNode currentNode, String
nodeId, boolean isPattern) {
- return currentNode.getChild(nodeId, isPattern);
- }
- };
-
- private IdParser idParser;
-
- private boolean limitRender;
-
- // The client ids to visit
- private Collection<String> clientIds;
-
- private Collection<String> shortIds;
-
- // Our visit hints
- private Set<VisitHint> hints;
-
- private ComponentMatcherNode rootNode;
-
- private Map<String, ComponentMatcherNode> directNodesMap;
-
- /**
- * Creates a PartialVisitorContext instance.
- *
- * @param facesContext
- * the FacesContext for the current request
- * @param clientIds
- * the client ids of the components to visit
- * @throws NullPointerException
- * if {@code facesContext} is {@code null}
- */
- public ExtendedPartialVisitContext(FacesContext facesContext,
Collection<String> clientIds, boolean limitRender) {
- this(facesContext, clientIds, null, limitRender);
- }
-
- /**
- * Creates a PartialVisitorContext instance with the specified hints.
- *
- * @param facesContext
- * the FacesContext for the current request
- * @param clientIds
- * the client ids of the components to visit
- * @param hints
- * a the VisitHints for this visit
- * @throws NullPointerException
- * if {@code facesContext} is {@code null}
- */
- public ExtendedPartialVisitContext(FacesContext facesContext,
Collection<String> clientIds, Set<VisitHint> hints,
- boolean limitRender) {
-
- super(facesContext, ExtendedVisitContextMode.RENDER);
-
- // Initialize our various collections
- initializeCollections(clientIds);
-
- // Copy and store hints - ensure unmodifiable and non-empty
- EnumSet<VisitHint> hintsEnumSet = ((hints == null) || (hints.isEmpty())) ?
EnumSet.noneOf(VisitHint.class)
- : EnumSet.copyOf(hints);
-
- this.hints = Collections.unmodifiableSet(hintsEnumSet);
-
- this.limitRender = limitRender;
- }
-
- private IdParser setupIdParser(String id) {
- if (idParser == null) {
- idParser = new
IdParser(UINamingContainer.getSeparatorChar(getFacesContext()),
- MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR);
- }
-
- idParser.setId(id);
-
- return idParser;
- }
-
- private ComponentMatcherNode findMatchingNode(String clientId) {
- ComponentMatcherNode node = rootNode;
-
- IdParser idParser = setupIdParser(clientId);
-
- while (node != null && idParser.findNext()) {
- String componentId = idParser.getComponentId();
- String metadataComponentId = idParser.getMetadataComponentId();
-
- if (metadataComponentId != null) {
- node = node.getChild(componentId, false);
- if (node != null) {
- node = node.getChild(metadataComponentId, false);
- }
- } else {
- node = node.getMatchedChild(componentId);
- }
- }
-
- return node;
- }
-
- private ComponentMatcherNode findAddedNode(String clientId) {
- ComponentMatcherNode node = findMatchingNode(clientId);
-
- if (node != null && !node.isAdded()) {
- node = null;
- }
-
- return node;
- }
-
- private void removeNode(ComponentMatcherNode nodeToRemove) {
- nodeToRemove.markRemoved();
-
- ComponentMatcherNode node = nodeToRemove;
- while (node != null && !node.hasDirectChildren()) {
- ComponentMatcherNode parentNode = node.getParentNode();
- if (parentNode != null) {
- parentNode.removeChild(node);
- node = parentNode;
- } else {
- break;
- }
- }
- }
-
- private boolean invokeNodeOperation(NodeOperationCommand command,
ComponentMatcherNode currentNode,
- IdTreeNode idTreeNode, StringBuilder sb) {
-
- String componentId = idTreeNode.getComponentId();
- String metadataComponentId = idTreeNode.getMetadataComponentId();
-
- ComponentMatcherNode nextNode;
-
- if (metadataComponentId != null) {
- nextNode = command.getNextNode(currentNode, componentId, false);
- if (nextNode != null) {
- nextNode = command.getNextNode(nextNode, metadataComponentId, false);
- }
- } else {
- boolean isPattern = ANY_WILDCARD.equals(componentId);
- nextNode = command.getNextNode(currentNode, componentId, isPattern);
- }
-
- boolean result = false;
-
- if (nextNode != null) {
- final int bufferLength = sb.length();
- if (bufferLength != 0) {
- //TODO replace with constant
- sb.append(':');
- }
- sb.append(componentId);
- if (metadataComponentId != null) {
- sb.append(metadataComponentId);
- }
-
- List<IdTreeNode> idTreeChildNodes = idTreeNode.getChildNodes();
- if (idTreeChildNodes != null) {
- final int newBufferLength = sb.length();
-
- for (IdTreeNode idTreeChildNode : idTreeChildNodes) {
- result |= invokeNodeOperation(command, nextNode, idTreeChildNode,
sb);
-
- sb.setLength(newBufferLength);
- }
- } else {
- result |= command.processLastNode(nextNode, sb.toString());
- }
-
- sb.setLength(bufferLength);
- }
-
- return result;
- }
-
- private boolean invokeRootNodeOperation(NodeOperationCommand command, IdTreeNode
idTreeNode) {
- boolean result = false;
-
- List<IdTreeNode> idTreeChildNodes = idTreeNode.getChildNodes();
- if (idTreeChildNodes != null) {
- StringBuilder sb = new StringBuilder();
-
- for (IdTreeNode idTreeChildNode : idTreeChildNodes) {
- result |= invokeNodeOperation(command, rootNode, idTreeChildNode, sb);
- }
- }
-
- return result;
- }
-
- private boolean addNode(String patternId) {
- IdTreeNode idTreeNode = new IdTreeNode();
- idTreeNode.appendNodesFromParser(setupIdParser(patternId));
-
- return invokeRootNodeOperation(addNodeOperation, idTreeNode);
- }
-
- private boolean removeNode(String patternId) {
- IdTreeNode idTreeNode = new IdTreeNode();
- idTreeNode.appendNodesFromParser(setupIdParser(patternId));
-
- return invokeRootNodeOperation(removeNodeOperation, idTreeNode);
- }
-
- /**
- * @see VisitContext#getHints VisitContext.getHints
- */
- @Override
- public Set<VisitHint> getHints() {
- return hints;
- }
-
- /**
- * @see VisitContext#getIdsToVisit VisitContext.getIdsToVisit()
- */
- @Override
- public Collection<String> getIdsToVisit() {
-
- // We just return our clientIds collection. This is
- // the modifiable (but proxied) collection of all of
- // the client ids to visit.
- return clientIds;
- }
-
- /**
- * @see VisitContext#getSubtreeIdsToVisit VisitContext.getSubtreeIdsToVisit()
- */
- @Override
- public Collection<String> getSubtreeIdsToVisit(UIComponent component) {
-
- // Make sure component is a NamingContainer
- if (!(component instanceof NamingContainer)) {
- throw new IllegalArgumentException("Component is not a NamingContainer:
" + component);
- }
-
- if (!limitRender &&
PartialViewContextAjaxOutputTracker.hasNestedAjaxOutputs(component)) {
- return VisitContext.ALL_IDS;
- }
-
- String clientId = buildExtendedClientId(component);
-
- ComponentMatcherNode node = findMatchingNode(clientId);
-
- Collection<String> result = null;
-
-
- if (node != null) {
- if (node.hasKidPatternNodes()) {
- result = VisitContext.ALL_IDS;
- } else {
- Collection<String> subtreeIds = node.getSubtreeIds();
- if (subtreeIds != null) {
- result = Collections.unmodifiableCollection(subtreeIds);
- } else {
- //TODO nick - this code addresses the case of parent pattern nodes,
and can be optimized
- if (node.hasDirectIdChildren()) {
- result = VisitContext.ALL_IDS;
- } else {
- result = Collections.emptySet();
- }
- }
- }
- } else {
- result = Collections.emptySet();
- }
-
- return result;
- }
-
- public Collection<String>getDirectSubtreeIdsToVisit(UIComponent component) {
- // Make sure component is a NamingContainer
- if (!(component instanceof NamingContainer)) {
- throw new IllegalArgumentException("Component is not a NamingContainer:
" + component);
- }
-
- String clientId = component.getClientId(getFacesContext());
- ComponentMatcherNode node = findMatchingNode(clientId);
-
- if (node != null && node.hasDirectPatternChildren()) {
- return VisitContext.ALL_IDS;
- }
-
- Set<String> result = null;
- if (node != null && node.hasDirectIdChildren()) {
- result = new HashSet<String>();
- result.addAll(node.getIdChildren().keySet());
- }
-
- if (!limitRender) {
-
- Collection<String> directChildrenIds =
PartialViewContextAjaxOutputTracker.getDirectChildrenIds(component);
- if (directChildrenIds != null && !directChildrenIds.isEmpty()) {
- if (result == null) {
- result = new HashSet<String>();
- }
-
- result.addAll(directChildrenIds);
- }
- }
-
- if (result != null && !result.isEmpty()) {
- return Collections.unmodifiableCollection(result);
- } else {
- return Collections.emptySet();
- }
- }
-
- /**
- * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
- */
- @Override
- public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
{
- if (shortIds.contains(component.getId())) {
- String clientId = buildExtendedClientId(component);
- ComponentMatcherNode node = findAddedNode(clientId);
- if (node != null) {
- VisitResult visitResult = callback.visit(this, component);
-
- removeNode(clientId);
-
- if (clientIds.isEmpty() && limitRender) {
- return VisitResult.COMPLETE;
- } else {
- return visitResult;
- }
- }
- }
-
- if (!limitRender) {
- if (component instanceof AjaxOutput) {
- AjaxOutput ajaxOutput = (AjaxOutput) component;
- if (ajaxOutput.isAjaxRendered()) {
-
- // TODO - remove explicit nested IDs from update
- return callback.visit(this, component);
- }
- }
- }
-
- return VisitResult.ACCEPT;
- }
-
- // Called to initialize our various collections.
- private void initializeCollections(Collection<String> clientIds) {
- this.rootNode = new ComponentMatcherNode();
- this.directNodesMap = new HashMap<String, ComponentMatcherNode>();
- this.shortIds = new HashSet<String>();
- this.clientIds = new CollectionProxy();
- this.clientIds.addAll(clientIds);
- }
-
- public VisitContext createNamingContainerVisitContext(UIComponent component,
Collection<String> directIds) {
- return new NamingContainerVisitContext(getFacesContext(), getVisitMode(),
component, directIds);
- }
-}
Modified: trunk/core/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/core/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -185,15 +185,54 @@
return wrappedViewContext.getPartialResponseWriter();
}
+ private boolean isProcessedExecutePhase(PhaseId phaseId) {
+ return phaseId == PhaseId.APPLY_REQUEST_VALUES || phaseId ==
PhaseId.PROCESS_VALIDATIONS
+ || phaseId == PhaseId.UPDATE_MODEL_VALUES;
+ }
+
@Override
public void processPartial(PhaseId phaseId) {
- if (detectContextMode() == ContextMode.DIRECT && phaseId ==
PhaseId.RENDER_RESPONSE) {
- processPartialRenderPhase();
+ if (detectContextMode() == ContextMode.DIRECT) {
+ if (phaseId == PhaseId.RENDER_RESPONSE) {
+ processPartialRenderPhase();
+ } else if (isProcessedExecutePhase(phaseId)) {
+ processPartialExecutePhase(phaseId);
+ }
} else {
wrappedViewContext.processPartial(phaseId);
}
}
+ protected void processPartialExecutePhase(PhaseId phaseId) {
+ PartialViewContext pvc = facesContext.getPartialViewContext();
+ Collection <String> executeIds = pvc.getExecuteIds();
+
+ if (executeIds == null || executeIds.isEmpty()) {
+ if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
+ LOG.warn("Partial execute won't happen - executeIds were not
specified");
+ }
+ return;
+ }
+
+ try {
+ executeComponents(phaseId, executeIds);
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ }
+
+ if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
+ PartialResponseWriter writer = pvc.getPartialResponseWriter();
+ facesContext.setResponseWriter(writer);
+ }
+ }
+
+ protected void executeComponents(PhaseId phaseId, Collection<String>
executeIds) {
+ EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
+ VisitContext visitContext = new ExecuteExtendedVisitContext(facesContext,
executeIds, hints);
+ PartialViewExecuteVisitCallback callback = new
PartialViewExecuteVisitCallback(facesContext, phaseId);
+ facesContext.getViewRoot().visitTree(visitContext, callback);
+ }
+
protected void processPartialRenderPhase() {
PartialViewContext pvc = facesContext.getPartialViewContext();
UIViewRoot viewRoot = facesContext.getViewRoot();
@@ -223,7 +262,7 @@
(!limitRender &&
PartialViewContextAjaxOutputTracker.hasNestedAjaxOutputs(viewRoot))) {
EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
- VisitContext visitContext = new ExtendedPartialVisitContext(facesContext,
phaseIds, hints, limitRender);
+ VisitContext visitContext = new RenderExtendedVisitContext(facesContext,
phaseIds, hints, limitRender);
VisitCallback visitCallback = new RenderVisitCallback(facesContext);
viewRoot.visitTree(visitContext, visitCallback);
}
@@ -369,9 +408,10 @@
}
private boolean visitActivatorComponent(String componentActivatorId, VisitCallback
visitCallback) {
+
Set<String> idsToVisit = Collections.singleton(componentActivatorId);
Set<VisitHint> visitHints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
- VisitContext visitContext = VisitContext.createVisitContext(facesContext,
idsToVisit, visitHints);
+ VisitContext visitContext = new ExecuteExtendedVisitContext(facesContext,
idsToVisit, visitHints);
boolean visitResult = facesContext.getViewRoot().visitTree(visitContext,
visitCallback);
return visitResult;
Added:
trunk/core/impl/src/main/java/org/richfaces/context/PartialViewExecuteVisitCallback.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/context/PartialViewExecuteVisitCallback.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/context/PartialViewExecuteVisitCallback.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -0,0 +1,66 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.context;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
+import javax.faces.component.visit.VisitResult;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PhaseId;
+
+import org.richfaces.component.MetaComponentProcessor;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+final class PartialViewExecuteVisitCallback implements VisitCallback {
+
+ private FacesContext facesContext;
+
+ private PhaseId phaseId;
+
+ PartialViewExecuteVisitCallback(FacesContext context, PhaseId phaseId) {
+ super();
+ this.facesContext = context;
+ this.phaseId = phaseId;
+ }
+
+ public VisitResult visit(VisitContext context, UIComponent target) {
+ String metaComponentId = (String)
facesContext.getAttributes().get(ExtendedVisitContext.META_COMPONENT_ID);
+ if (metaComponentId != null) {
+ MetaComponentProcessor executor = (MetaComponentProcessor) target;
+ executor.processMetaComponent(facesContext, metaComponentId);
+ } else if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
+ target.processDecodes(facesContext);
+ } else if (phaseId == PhaseId.PROCESS_VALIDATIONS) {
+ target.processValidators(facesContext);
+ } else if (phaseId == PhaseId.UPDATE_MODEL_VALUES) {
+ target.processUpdates(facesContext);
+ } else {
+ throw new IllegalArgumentException(phaseId.toString());
+ }
+
+ return VisitResult.REJECT;
+ }
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/context/RenderExtendedVisitContext.java
===================================================================
--- trunk/core/impl/src/main/java/org/richfaces/context/RenderExtendedVisitContext.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/context/RenderExtendedVisitContext.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -0,0 +1,81 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.context;
+
+import java.util.Collection;
+import java.util.Set;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitHint;
+import javax.faces.component.visit.VisitResult;
+import javax.faces.context.FacesContext;
+
+import org.ajax4jsf.component.AjaxOutput;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class RenderExtendedVisitContext extends BaseExtendedVisitContext {
+
+ private boolean limitRender;
+
+ public RenderExtendedVisitContext(FacesContext facesContext, Collection<String>
clientIds, Set<VisitHint> hints,
+ boolean limitRender) {
+ super(facesContext, clientIds, hints, ExtendedVisitContextMode.RENDER);
+
+ this.limitRender = limitRender;
+ }
+
+ @Override
+ protected boolean hasImplicitSubtreeIdsToVisit(UIComponent component) {
+ return !limitRender &&
PartialViewContextAjaxOutputTracker.hasNestedAjaxOutputs(component);
+ }
+
+ protected void addDirectSubtreeIdsToVisitForImplicitComponents(UIComponent component,
Set<String> result) {
+ if (!limitRender) {
+ Collection<String> directChildrenIds =
PartialViewContextAjaxOutputTracker.getDirectChildrenIds(component);
+ if (directChildrenIds != null && !directChildrenIds.isEmpty()) {
+ result.addAll(directChildrenIds);
+ }
+ }
+ }
+
+ protected VisitResult invokeVisitCallbackForImplicitComponent(UIComponent component,
VisitCallback callback) {
+ if (!limitRender) {
+ if (component instanceof AjaxOutput) {
+ AjaxOutput ajaxOutput = (AjaxOutput) component;
+ if (ajaxOutput.isAjaxRendered()) {
+
+ // TODO - remove explicit nested IDs from update
+ return callback.visit(this, component);
+ }
+ }
+ }
+ return VisitResult.ACCEPT;
+ }
+
+ protected boolean shouldCompleteOnEmptyIds() {
+ return limitRender;
+ }
+}
Modified:
trunk/core/impl/src/main/java/org/richfaces/renderkit/util/CoreRendererUtils.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/renderkit/util/CoreRendererUtils.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/core/impl/src/main/java/org/richfaces/renderkit/util/CoreRendererUtils.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -37,7 +37,9 @@
import javax.faces.component.UIForm;
import javax.faces.context.FacesContext;
+import org.richfaces.component.MetaComponentResolver;
import org.richfaces.context.ComponentIdResolver;
+import org.richfaces.context.ExtendedVisitContext;
/**
* Util class for common render operations - render passthru html attributes,
@@ -71,6 +73,10 @@
} else if (NONE.equals(id)) {
return NONE;
} else if (THIS.equals(id)) {
+ String metaComponentId = (String)
facesContext.getAttributes().get(ExtendedVisitContext.META_COMPONENT_ID);
+ if (metaComponentId != null) {
+ return component.getClientId(facesContext) +
MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR + metaComponentId;
+ }
return component.getClientId(facesContext);
} else if (FORM.equals(id)) {
UIForm nestingForm = getNestingForm(facesContext, component);
Modified: trunk/core/impl/src/main/java/org/richfaces/resource/ResourceFactoryImpl.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/resource/ResourceFactoryImpl.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/core/impl/src/main/java/org/richfaces/resource/ResourceFactoryImpl.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -392,6 +392,8 @@
if (result != null) {
result.setLibraryName(resourceKey.getLibraryName());
result.setResourceName(resourceKey.getResourceName());
+ } else if (mappedResourceData != null) {
+ result = defaultHandler.createResource(actualKey.getResourceName(),
actualKey.getLibraryName());
}
return result;
Modified: trunk/core/impl/src/main/resources/META-INF/resources/richfaces.js
===================================================================
--- trunk/core/impl/src/main/resources/META-INF/resources/richfaces.js 2010-10-30 00:25:36
UTC (rev 19792)
+++ trunk/core/impl/src/main/resources/META-INF/resources/richfaces.js 2010-10-31 13:42:28
UTC (rev 19793)
@@ -532,6 +532,10 @@
parameters.execute = "@component";
parameters.render = "@component";
+ if (options.clientParameters) {
+ jQuery.extend(parameters, options.clientParameters);
+ }
+
if (!parameters["org.richfaces.ajax.component"]) {
parameters["org.richfaces.ajax.component"] = sourceId;
}
Modified: trunk/core/impl/src/test/java/org/richfaces/context/AjaxTableComponentImpl.java
===================================================================
---
trunk/core/impl/src/test/java/org/richfaces/context/AjaxTableComponentImpl.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/core/impl/src/test/java/org/richfaces/context/AjaxTableComponentImpl.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -41,7 +41,7 @@
public class AjaxTableComponentImpl extends UIData {
private static final Logger LOG = RichfacesLogger.COMPONENTS.getLogger();
-
+
private boolean visitMetaComponent(String name, ExtendedVisitContext visitContext,
VisitCallback callback) {
UIComponent facet = getFacet(name);
if (facet != null) {
@@ -107,7 +107,7 @@
// Visit children, short-circuiting as necessary
if ((result == VisitResult.ACCEPT) && doVisitChildren(visitContext))
{
setRowIndex(-1);
-
+
if (visitFixedChildren(visitContext, callback)) {
return true;
}
@@ -133,7 +133,7 @@
// Return false to allow the visit to continue
return false;
}
-
+
protected boolean visitFixedChildren(VisitContext visitContext, VisitCallback
callback) {
if (visitContext instanceof ExtendedVisitContext) {
@@ -154,32 +154,32 @@
return true;
}
}
-
+
return false;
}
}
protected boolean visitDataChildren(VisitContext visitContext, VisitCallback
callback) {
int rowIndex = 0;
-
+
for (setRowIndex(rowIndex); isRowAvailable(); setRowIndex(++rowIndex)) {
VisitResult result = visitContext.invokeVisitCallback(this, callback);
-
+
if (result == VisitResult.COMPLETE) {
return true;
}
-
+
if (result == VisitResult.REJECT) {
continue;
}
-
+
for (UIComponent child: getChildren()) {
if (child.visitTree(visitContext, callback)) {
return true;
}
}
}
-
+
return false;
}
Modified:
trunk/core/impl/src/test/java/org/richfaces/context/ExtendedPartialVisitContextTest.java
===================================================================
---
trunk/core/impl/src/test/java/org/richfaces/context/ExtendedPartialVisitContextTest.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/core/impl/src/test/java/org/richfaces/context/ExtendedPartialVisitContextTest.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -46,6 +46,7 @@
import javax.faces.application.Application;
import javax.faces.component.UIColumn;
import javax.faces.component.UIComponent;
+import javax.faces.component.UIData;
import javax.faces.component.UIForm;
import javax.faces.component.UIOutput;
import javax.faces.component.UIViewRoot;
@@ -150,7 +151,7 @@
private List<String> tableData;
- private ExtendedPartialVisitContext renderingContext;
+ private BaseExtendedVisitContext renderingContext;
private TrackingVisitCallback trackingVisitCallback;
@@ -163,13 +164,17 @@
private UIOutput nestedTableFooter;
private static void assertEqualSets(Collection<?> expected, Collection<?>
actual) {
- assertEquals(asSet(expected), asSet(actual));
+ assertEquals(asComparableCollection(expected), asComparableCollection(actual));
}
- private static <T> Set<T> asSet(Collection<T> c) {
- if (c instanceof Set) {
- return (Set) c;
+ private static <T> Collection<T>
asComparableCollection(Collection<T> c) {
+ if (c instanceof Set || c instanceof List) {
+ return c;
} else {
+ if (c == VisitContext.ALL_IDS) {
+ return c;
+ }
+
if (c != null) {
return new HashSet<T>(c);
} else {
@@ -188,7 +193,7 @@
}
private void createVisitContext(boolean limitRender) {
- renderingContext = new ExtendedPartialVisitContext(facesContext,
Collections.<String>emptySet(),
+ renderingContext = new RenderExtendedVisitContext(facesContext,
Collections.<String>emptySet(),
EnumSet.<VisitHint>of(VisitHint.SKIP_UNRENDERED), limitRender);
}
Modified: trunk/core/impl/src/test/resources/javascript/4_0_0.html
===================================================================
--- trunk/core/impl/src/test/resources/javascript/4_0_0.html 2010-10-30 00:25:36 UTC (rev
19792)
+++ trunk/core/impl/src/test/resources/javascript/4_0_0.html 2010-10-31 13:42:28 UTC (rev
19793)
@@ -164,6 +164,25 @@
RichFaces.ajax(ajaxSource, ajaxEvent, ajaxOptions);
});
+ test("RichFaces.ajax client parameters test", function() {
+ expect(7);
+ var ajaxSource = "source";
+ var ajaxEvent = "event";
+ var ajaxOptions = {clientParameters: {'param': 'value'}, incId: 1};
+ jsf.ajax = {
+ request : function(source, event, options) {
+ equals(source, ajaxSource);
+ equals(event, ajaxEvent);
+ equals(options['execute'], '@component');
+ equals(options['render'], '@component');
+ equals(options['param'], 'value');
+ equals(options['org.richfaces.ajax.component'], 'source');
+ equals(options['source'], 'source');
+ }
+ }
+ RichFaces.ajax(ajaxSource, ajaxEvent, ajaxOptions);
+ });
+
test("RichFaces.escapeCSSMetachars test", function() {
expect(6);
Modified:
trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/TreeNodeParser.java
===================================================================
---
trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/TreeNodeParser.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/TreeNodeParser.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -99,18 +99,18 @@
currentNode.addChild(newNode);
}
- currentNode.setData(JOINER.join(currentNode.getData(),
localName.toLowerCase(Locale.US), " ["));
+ newNode.setData(JOINER.join(newNode.getData(), localName.toLowerCase(Locale.US),
" ["));
currentNode = newNode;
}
public void endElement(String uri, String localName, String qName) throws
SAXException {
- currentNode.setData(JOINER.join("]", currentNode.getData()));
+ currentNode.setData(JOINER.join(currentNode.getData(), "]"));
currentNode = (SwingTreeNodeImpl) currentNode.getParent();
}
public void characters(char[] ch, int start, int length) throws SAXException {
- currentNode.setData(JOINER.join(currentNode.getData(), new String(ch, start,
length)));
+ currentNode.setData(JOINER.join(currentNode.getData(), new String(ch, start,
length).trim()));
}
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
{
Modified: trunk/examples/iteration-demo/src/main/webapp/tree.xhtml
===================================================================
--- trunk/examples/iteration-demo/src/main/webapp/tree.xhtml 2010-10-30 00:25:36 UTC (rev
19792)
+++ trunk/examples/iteration-demo/src/main/webapp/tree.xhtml 2010-10-31 13:42:28 UTC (rev
19793)
@@ -3,7 +3,7 @@
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
-
xmlns:it="http://richfaces.org/iteration">
+
xmlns:it="http://richfaces.org/tree">
<f:view contentType="text/html" />
<h:head>
@@ -18,5 +18,11 @@
</h:panelGroup>
</it:treeNode>
</it:tree>
+
+ <h:form>
+ <h:commandLink value="Re-render">
+ <f:ajax render=":tree" />
+ </h:commandLink>
+ </h:form>
</h:body>
</html>
Modified: trunk/ui/common/ui/src/main/java/org/richfaces/component/UIDataAdaptor.java
===================================================================
--- trunk/ui/common/ui/src/main/java/org/richfaces/component/UIDataAdaptor.java 2010-10-30
00:25:36 UTC (rev 19792)
+++ trunk/ui/common/ui/src/main/java/org/richfaces/component/UIDataAdaptor.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -292,6 +292,15 @@
return DataVisitResult.STOP;
}
+
+ if (result == VisitResult.ACCEPT) {
+ result = visitDataChildrenMetaComponents((ExtendedVisitContext)
visitContext, callback);
+ if (VisitResult.COMPLETE.equals(result)) {
+ visitResult = true;
+
+ return DataVisitResult.STOP;
+ }
+ }
}
if (VisitResult.ACCEPT.equals(result)) {
@@ -1013,10 +1022,16 @@
serializableModel.update();
}
+
+ doUpdate();
popComponentFromEL(faces);
}
+ protected void doUpdate() {
+
+ }
+
@Override
public void setId(String id) {
super.setId(id);
@@ -1342,6 +1357,10 @@
return visitComponents(fixedChildren(), visitContext, callback);
}
+ protected VisitResult visitDataChildrenMetaComponents(ExtendedVisitContext
extendedVisitContext, VisitCallback callback) {
+ return VisitResult.ACCEPT;
+ }
+
protected boolean visitDataChildren(VisitContext visitContext, VisitCallback
callback, boolean visitRows) {
if (visitRows) {
Modified: trunk/ui/common/ui/src/main/java/org/richfaces/component/util/HtmlUtil.java
===================================================================
--- trunk/ui/common/ui/src/main/java/org/richfaces/component/util/HtmlUtil.java 2010-10-30
00:25:36 UTC (rev 19792)
+++ trunk/ui/common/ui/src/main/java/org/richfaces/component/util/HtmlUtil.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -128,10 +128,11 @@
return false;
}
- private static String concat(char separator, String... strings) {
+ private static String concat(char separator, Object... objects) {
StringBuilder result = new StringBuilder();
- for (String s : strings) {
+ for (Object o : objects) {
+ String s = (String) o;
if (!Strings.isNullOrEmpty(s)) {
if (result.length() != 0) {
result.append(separator);
@@ -144,11 +145,11 @@
return result.toString();
}
- public static String concatClasses(String... classes) {
+ public static String concatClasses(Object... classes) {
return concat(' ', classes);
}
- public static String concatStyles(String... styles) {
+ public static String concatStyles(Object... styles) {
return concat(';', styles);
}
}
Modified: trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/AjaxEventOptions.java
===================================================================
---
trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/AjaxEventOptions.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/AjaxEventOptions.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -21,23 +21,23 @@
package org.richfaces.renderkit;
-import org.ajax4jsf.javascript.ScriptStringBase;
-import org.ajax4jsf.javascript.ScriptUtils;
-
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
+import org.ajax4jsf.javascript.ScriptStringBase;
+import org.ajax4jsf.javascript.ScriptUtils;
+
/**
* @author Nick Belaevski
* @since 4.0
*/
public class AjaxEventOptions extends ScriptStringBase {
- /**
- *
- */
public static final String PARAMETERS = "parameters";
+
+ public static final String CLIENT_PARAMETERS = "clientParameters";
+
private Map<String, Object> options = new HashMap<String, Object>();
public void appendScript(StringBuffer functionString) {
@@ -100,4 +100,20 @@
parameters.remove(parameterName);
}
}
+
+ public Object getClientParameters() {
+ return options.get(CLIENT_PARAMETERS);
+ }
+
+ public void setClientParameters(Object value) {
+ options.put(CLIENT_PARAMETERS, value);
+ }
+
+ public Object getAjaxComponent() {
+ return getParameter(AjaxConstants.AJAX_COMPONENT_ID_PARAMETER);
+ }
+
+ public void setAjaxComponent(Object ajaxComponent) {
+ getParameters().put(AjaxConstants.AJAX_COMPONENT_ID_PARAMETER, ajaxComponent);
+ }
}
Modified: trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/RendererBase.java
===================================================================
--- trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/RendererBase.java 2010-10-30
00:25:36 UTC (rev 19792)
+++ trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/RendererBase.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -29,6 +29,7 @@
import javax.faces.render.Renderer;
import org.ajax4jsf.Messages;
+import org.richfaces.component.util.HtmlUtil;
import org.richfaces.log.Logger;
import org.richfaces.log.RichfacesLogger;
import org.richfaces.renderkit.util.RendererUtils;
@@ -281,4 +282,11 @@
}
}
+ public String concatClasses(Object... objects) {
+ return HtmlUtil.concatClasses(objects);
+ }
+
+ public String concatStyles(Object... objects) {
+ return HtmlUtil.concatStyles(objects);
+ }
}
Modified:
trunk/ui/input/ui/src/main/java/org/richfaces/renderkit/AutocompleteRendererBase.java
===================================================================
---
trunk/ui/input/ui/src/main/java/org/richfaces/renderkit/AutocompleteRendererBase.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/ui/input/ui/src/main/java/org/richfaces/renderkit/AutocompleteRendererBase.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -291,4 +291,8 @@
throw new IllegalArgumentException(metaComponentId);
}
}
+
+ public void decodeMetaComponent(FacesContext context, UIComponent component, String
metaComponentId) {
+ throw new UnsupportedOperationException();
+ }
}
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/AbstractTableRenderer.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/AbstractTableRenderer.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/AbstractTableRenderer.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -596,6 +596,10 @@
}
}
+ public void decodeMetaComponent(FacesContext context, UIComponent component, String
metaComponentId) {
+ throw new UnsupportedOperationException();
+ }
+
protected void partialStart(FacesContext facesContext, String id) throws IOException
{
facesContext.getPartialViewContext().getPartialResponseWriter().startUpdate(id);
}
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/DataGridRenderer.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/DataGridRenderer.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/DataGridRenderer.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -275,6 +275,9 @@
}
}
+ public void decodeMetaComponent(FacesContext context, UIComponent component, String
metaComponentId) {
+ throw new UnsupportedOperationException();
+ }
@Override
protected void doCleanup(FacesContext context, RowHolderBase rowHolder) throws
IOException {
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/ExtendedDataTableRenderer.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/ExtendedDataTableRenderer.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/ExtendedDataTableRenderer.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -575,6 +575,10 @@
}
}
+ public void decodeMetaComponent(FacesContext context, UIComponent component, String
metaComponentId) {
+ throw new UnsupportedOperationException();
+ }
+
protected void doEncodeBegin(ResponseWriter writer, FacesContext context, UIComponent
component)
throws IOException {
Map<String, Object> attributes = component.getAttributes();
Modified:
trunk/ui/output/ui/src/main/java/org/richfaces/renderkit/html/TooltipRenderer.java
===================================================================
---
trunk/ui/output/ui/src/main/java/org/richfaces/renderkit/html/TooltipRenderer.java 2010-10-30
00:25:36 UTC (rev 19792)
+++
trunk/ui/output/ui/src/main/java/org/richfaces/renderkit/html/TooltipRenderer.java 2010-10-31
13:42:28 UTC (rev 19793)
@@ -23,28 +23,28 @@
package org.richfaces.renderkit.html;
-import org.ajax4jsf.context.AjaxContext;
-import org.ajax4jsf.javascript.JSObject;
-import org.richfaces.TooltipMode;
-import org.richfaces.component.AbstractTooltip;
-import org.richfaces.component.html.HtmlTooltip;
-import org.richfaces.renderkit.HtmlConstants;
-import org.richfaces.renderkit.MetaComponentRenderer;
+import static org.richfaces.renderkit.RenderKitUtils.renderPassThroughAttributes;
+import static org.richfaces.renderkit.html.TogglePanelRenderer.addEventOption;
+import static org.richfaces.renderkit.html.TogglePanelRenderer.getAjaxOptions;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialResponseWriter;
import javax.faces.context.ResponseWriter;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import static org.richfaces.component.util.HtmlUtil.concatClasses;
-import static org.richfaces.renderkit.RenderKitUtils.renderPassThroughAttributes;
-import static org.richfaces.renderkit.html.TogglePanelRenderer.addEventOption;
-import static org.richfaces.renderkit.html.TogglePanelRenderer.getAjaxOptions;
+import org.ajax4jsf.context.AjaxContext;
+import org.ajax4jsf.javascript.JSObject;
+import org.richfaces.TooltipMode;
+import org.richfaces.component.AbstractTooltip;
+import org.richfaces.component.html.HtmlTooltip;
+import org.richfaces.renderkit.HtmlConstants;
+import org.richfaces.renderkit.MetaComponentRenderer;
/**
* @author amarkhel
@@ -215,6 +215,10 @@
}
}
+ public void decodeMetaComponent(FacesContext context, UIComponent component, String
metaComponentId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
protected Class<? extends UIComponent> getComponentClass() {
return AbstractTooltip.class;