You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ar...@apache.org on 2012/09/24 18:02:27 UTC

svn commit: r1389453 - in /myfaces/trinidad/branches/ar_1940: trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/tagDemos/ trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/ trinidad-examples/trinidad-demo/src/main/weba...

Author: arobinson74
Date: Mon Sep 24 16:02:26 2012
New Revision: 1389453

URL: http://svn.apache.org/viewvc?rev=1389453&view=rev
Log:
Commit changes that have been in my working copy

Added:
    myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/
    myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorder.jspx   (with props)
    myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorderMap.jspx   (with props)
    myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach2.jspx   (with props)
Modified:
    myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/tagDemos/ForEachBean.java
    myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml
    myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach.jspx
    myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java

Modified: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/tagDemos/ForEachBean.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/tagDemos/ForEachBean.java?rev=1389453&r1=1389452&r2=1389453&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/tagDemos/ForEachBean.java (original)
+++ myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/java/org/apache/myfaces/trinidaddemo/tagDemos/ForEachBean.java Mon Sep 24 16:02:26 2012
@@ -1,10 +1,14 @@
 package org.apache.myfaces.trinidaddemo.tagDemos;
 
+import java.io.Serializable;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.faces.component.UIComponent;
 import javax.faces.component.visit.VisitCallback;
@@ -25,17 +29,19 @@ import org.apache.myfaces.trinidad.model
 
 
 public class ForEachBean
+  implements Serializable
 {
   public static class Person
+    implements Serializable
   {
     public Person(
       String key,
       String firstName,
       String lastName)
     {
-      this._firstName = firstName;
-      this._lastName = lastName;
-      this._key = key;
+      _firstName = firstName;
+      _lastName = lastName;
+      _key = key;
     }
 
     public final String getKey()
@@ -62,24 +68,43 @@ public class ForEachBean
     private final String _key;
     private final String _firstName;
     private final String _lastName;
+
+    @SuppressWarnings("compatibility:-1476456984616362784")
+    private static final long serialVersionUID = 1L;
   }
 
   public ForEachBean()
   {
-    _simpleList = Arrays.asList(
-                    "One", "Two", "Three", "Four");
-    _model = new RowKeyPropertyModel(
-               Arrays.asList(
-                 new Person("a", "John", "Doe"),
-                 new Person("b", "Jane", "Doe"),
-                 new Person("c", "Bob", "Smith"),
-                 new Person("d", "Alice", "Jones")),
-               "key");
+    _list = new ArrayList<Person>(
+      Arrays.asList(
+        new Person("a", "John", "Doe"),
+        new Person("b", "Jane", "Doe"),
+        new Person("c", "Bob", "Smith"),
+        new Person("d", "Alice", "Jones")));
+
+    _model = new RowKeyPropertyModel(new ArrayList<Person>(_list), "key");
+    _map = new LinkedHashMap<String, Person>();
+
+    _applySortToNonCollectionModelObjects();
+  }
+
+  public final void setCurrentExample(String currentExample)
+  {
+    _currentExample = currentExample;
+  }
+
+  public final String getCurrentExample()
+  {
+    return _currentExample;
   }
 
   public final void setSortProperty(String sortProperty)
   {
-    this._sortProperty = sortProperty;
+    if ("".equals(sortProperty))
+    {
+      sortProperty = null;
+    }
+    _sortProperty = sortProperty;
   }
 
   public final String getSortProperty()
@@ -89,7 +114,7 @@ public class ForEachBean
 
   public final void setSortAscending(boolean sortAscending)
   {
-    this._sortAscending = sortAscending;
+    _sortAscending = sortAscending;
   }
 
   public final boolean isSortAscending()
@@ -97,63 +122,119 @@ public class ForEachBean
     return _sortAscending;
   }
 
-  public List<String> getSimpleList()
+  public List<Person> getList()
   {
-    return _simpleList;
+    return _list;
   }
 
-  public void updateSortOrder(
-    ActionEvent evt)
+  public void updateSortOrder(ActionEvent evt)
   {
-    UIXCommand sourceComponent = (UIXCommand) evt.getComponent();
+    UIXCommand sourceComponent = (UIXCommand)evt.getComponent();
+    RowKeyPropertyModel model = _getCollectionModel();
 
     if (_sortProperty == null)
     {
-      _model.setSortCriteria(null);
+      model.setSortCriteria(null);
     }
     else
     {
-      _model.setSortCriteria(
-        Collections.singletonList(new SortCriterion(_sortProperty, _sortAscending)));
+      model.setSortCriteria(Collections.singletonList(new SortCriterion(_sortProperty,
+              _sortAscending)));
     }
 
     // Now fire a component event to re-order the components
-    Object origRowKey = _model.getRowKey();
     final FacesContext facesContext = FacesContext.getCurrentInstance();
+    List<String> orderedKeys = _applySortToNonCollectionModelObjects();
 
-    final List<String> orderedKeys = new ArrayList<String>(_model.getRowCount());
-    for (_model.setRowIndex(0);
-         _model.isRowAvailable();
-         _model.setRowIndex(_model.getRowIndex() + 1))
-    {
-      Person person = (Person)_model.getRowData();
-      orderedKeys.add(person.getKey());
-      System.out.println("Person: " + person);
-    }
-    _model.setRowKey(origRowKey);
-
-    for (UIComponent targetComponent :
-         RequestContext.getCurrentInstance().getPartialTargets(sourceComponent))
+    for (UIComponent targetComponent:
+      RequestContext.getCurrentInstance().getPartialTargets(sourceComponent))
     {
       String clientId = targetComponent.getClientId();
-      System.out.println("CLIENT ID: " + clientId);
+      //System.out.println("CLIENT ID: " + clientId);
       VisitTreeUtils.visitSingleComponent(facesContext, clientId,
-        new ReorderChildrenVisitCallback(orderedKeys));
+          new ReorderChildrenVisitCallback(orderedKeys));
     }
   }
 
+  public Map<String, Person> getMap()
+  {
+    return _map;
+  }
+
   public SortableModel getModel()
   {
+    return _getCollectionModel();
+  }
+
+  /**
+   * Applies the sort to the person list and the person map based on the sort order of the
+   * collection model.
+   * @return the sorted keys of the people to use for component reordering
+   */
+  private List<String> _applySortToNonCollectionModelObjects()
+  {
+    RowKeyPropertyModel model = _getCollectionModel();
+
+    Object origRowKey = model.getRowKey();
+    List<String> orderedKeys = new ArrayList<String>(model.getRowCount());
+    _list.clear();
+    _map.clear();
+    try
+    {
+      for (model.setRowIndex(0);
+        model.isRowAvailable();
+        model.setRowIndex(_model.getRowIndex() + 1))
+      {
+        Person person = (Person)model.getRowData();
+        orderedKeys.add(person.getKey());
+        //System.out.println("Person: " + person);
+        _list.add(person);
+        _map.put(person.getKey(), person);
+      }
+    }
+    finally
+    {
+      try
+      {
+        model.setRowKey(origRowKey);
+      }
+      catch (Throwable t)
+      {
+        ;
+      }
+    }
+
+    return orderedKeys;
+  }
+
+  private RowKeyPropertyModel _getCollectionModel()
+  {
+    if (_model == null)
+    {
+      // Model will be null as it is not serializable and the view state is not preserved in
+      // the server memory
+      _model = new RowKeyPropertyModel(new ArrayList<Person>(_list), "key");
+
+      if (_sortProperty == null)
+      {
+        _model.setSortCriteria(null);
+      }
+      else
+      {
+        _model.setSortCriteria(Collections.singletonList(new SortCriterion(_sortProperty,
+                _sortAscending)));
+      }
+    }
+
     return _model;
   }
 
   private static class ReorderChildrenVisitCallback
     implements VisitCallback, Comparator<String>
   {
-    private ReorderChildrenVisitCallback(
-      List<String> orderedKeys)
+    private ReorderChildrenVisitCallback(List<String> orderedKeys)
     {
-      this._orderedKeys = orderedKeys;
+      _orderedKeys = orderedKeys;
     }
 
     @Override
@@ -161,25 +242,20 @@ public class ForEachBean
       VisitContext visitContext,
       UIComponent  target)
     {
-      System.out.println("**************VISIT " + target.getClientId());
+      //System.out.println("**************VISIT " + target.getClientId());
       FacesContext facesContext = visitContext.getFacesContext();
       List<String> childrenIds = new ArrayList<String>();
-      for (UIComponent child : target.getChildren())
+      for (UIComponent child: target.getChildren())
       {
         // Safe to call get ID out of context
         childrenIds.add(child.getId());
       }
 
       Collections.sort(childrenIds, this);
-      System.out.println("Sorted list:");
-      for (String clientId : childrenIds)
-      {
-        System.out.println("  " + clientId);
-      }
 
       ChangeManager apm = RequestContext.getCurrentInstance().getChangeManager();
       apm.addComponentChange(facesContext, target,
-        new ReorderChildrenComponentChange(childrenIds));
+          new ReorderChildrenComponentChange(childrenIds));
 
       return VisitResult.COMPLETE;
     }
@@ -201,8 +277,13 @@ public class ForEachBean
     private final List<String> _orderedKeys;
   }
 
-  private final List<String> _simpleList;
-  private final RowKeyPropertyModel _model;
+  private final List<Person> _list;
+  private transient RowKeyPropertyModel _model;
+  private final Map<String, Person> _map;
+  private String _currentExample = "home";
   private String _sortProperty;
   private boolean _sortAscending;
-}
+
+  @SuppressWarnings("compatibility:-8911883817863052298")
+  private static final long serialVersionUID = 1L;
+}
\ No newline at end of file

Modified: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml?rev=1389453&r1=1389452&r2=1389453&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml (original)
+++ myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/faces-config.xml Mon Sep 24 16:02:26 2012
@@ -3143,6 +3143,8 @@
   <managed-bean>
     <managed-bean-name>forEachBean</managed-bean-name>
     <managed-bean-class>org.apache.myfaces.trinidaddemo.tagDemos.ForEachBean</managed-bean-class>
-    <managed-bean-scope>request</managed-bean-scope>
+    <!-- Use session scope since the session change manager is used, so that the bean stays in
+         sync with the change state -->
+    <managed-bean-scope>session</managed-bean-scope>
   </managed-bean>
 </faces-config>

Modified: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach.jspx
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach.jspx?rev=1389453&r1=1389452&r2=1389453&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach.jspx (original)
+++ myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach.jspx Mon Sep 24 16:02:26 2012
@@ -24,104 +24,58 @@
   <f:view>
     <tr:document title="ForEach Demo">
       <tr:form>
-        <tr:panelGroupLayout layout="vertical" partialTriggers="refreshButton">
-          <f:facet name="separator">
-            <tr:separator/>
+        <tr:panelBorderLayout>
+          <f:facet name="top">
+            <tr:panelGroupLayout layout="vertical" inlineStyle="padding-bottom: 2em;">
+              <tr:navigationPane hint="buttons">
+                <tr:commandNavigationItem text="Component Guide" action="guide"/>
+                <tr:commandNavigationItem destination="http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_forEach.html"
+                                          text="Tag Documentation"/>
+              </tr:navigationPane>
+            </tr:panelGroupLayout>
           </f:facet>
-          <tr:navigationPane hint="buttons">
-            <tr:commandNavigationItem immediate="true" text="Component Guide" action="guide"/>
-            <tr:commandNavigationItem immediate="true"
-                                      destination="http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_forEach.html"
-                                      text="Tag Documentation"/>
-          </tr:navigationPane>
-          <tr:goLink destination="http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_breadCrumbs.html"
-                     text="Tag Documentation"/>
-          <tr:outputFormatted styleUsage="instruction" value="&lt;b>forEach&lt;/b>"/>
-          <tr:panelGroupLayout layout="vertical">
-            <f:facet name="separator">
-              <tr:spacer height="12" />
-            </f:facet>
-            <tr:panelHeader text="Simple for each loop, no items">
-              <tr:panelGroupLayout layout="vertical">
-                <tr:forEach var="item" begin="0" end="2">
-                  <tr:outputText id="outputText" value="Client ID: #{component.clientId}"/>
-                </tr:forEach>
-              </tr:panelGroupLayout>
-            </tr:panelHeader>
-            <tr:panelHeader text="Simple for each loop, items from list">
-              <tr:panelGroupLayout layout="vertical">
-                <tr:forEach var="item" items="#{forEachBean.simpleList}">
-                  <tr:outputText id="outputText1" value="Client ID: #{component.clientId}"/>
-                </tr:forEach>
-              </tr:panelGroupLayout>
-            </tr:panelHeader>
-            <tr:panelHeader text="Simple for each loop, items from list, fixed IDs">
-              <tr:panelGroupLayout layout="vertical">
-                <tr:forEach var="item" items="#{forEachBean.simpleList}" varStatus="vs">
-                  <tr:outputText id="outputText2_${vs.key}"
-                                 value="Client ID: #{component.clientId}. Text: #{item}"/>
-                </tr:forEach>
-              </tr:panelGroupLayout>
-            </tr:panelHeader>
-            <tr:panelHeader text="Var status properties with list items">
-              <tr:panelGroupLayout layout="vertical">
-                <tr:forEach var="item" items="#{forEachBean.simpleList}" varStatus="vs">
-                  <tr:panelGroupLayout>
-                    <f:facet name="separator">
-                      <tr:spacer width="10"/>
-                    </f:facet>
-                    <tr:outputText value="Index: #{vs.index}"/>
-                    <tr:outputText value="Count: #{vs.count}"/>
-                    <tr:outputText value="Key: #{vs.key}"/>
-                    <tr:outputText value="First: #{vs.first}"/>
-                    <tr:outputText value="Last: #{vs.last}"/>
-                  </tr:panelGroupLayout>
-                  <tr:separator rendered="#{not vs.last}" />
-                </tr:forEach>
-              </tr:panelGroupLayout>
-            </tr:panelHeader>
-            <tr:panelHeader text="Reorder example with CollectionModel">
-              <tr:panelGroupLayout layout="vertical">
-                <tr:panelGroupLayout layout="vertical" id="personForEachParent"
-                                     partialTriggers="applySort">
-                  <tr:forEach var="person" items="#{forEachBean.model}" varStatus="vs">
-                    <tr:panelGroupLayout id="personPgl">
-                      <f:facet name="separator">
-                        <tr:spacer width="10"/>
-                      </f:facet>
-                      <tr:outputText id="firstName"
-                                     value="First name: #{person.firstName}"/>
-                      <tr:outputText id="lastName"
-                                     value="Last name: #{person.lastName}"/>
-                      <tr:outputText id="clientId"
-                                     value="(Panel group layout client ID: #{component.parent.clientId})"/>
-                    </tr:panelGroupLayout>
-                    <tr:separator id="sep1" rendered="#{not vs.last}" />
-                  </tr:forEach>
+          <f:facet name="start">
+            <tr:panelGroupLayout layout="scroll" inlineStyle="width: 250px; display: block">
+              <f:facet name="separator">
+                <tr:spacer height="6px"/>
+              </f:facet>
+              <tr:commandLink text="Re-order collection model"
+                              shortDesc="Example of reordering support with a collection model backed for each loop"
+                              partialSubmit="true" id="reorderCollectionModelLink">
+                <f:setPropertyActionListener target="#{forEachBean.currentExample}"
+                                             value="reorderCollectionModel"/>
+              </tr:commandLink>
+              <tr:commandLink text="Re-order map"
+                              shortDesc="Example of reordering support with a map backed for each loop"
+                              partialSubmit="true" id="reorderMapLink">
+                <f:setPropertyActionListener target="#{forEachBean.currentExample}"
+                                             value="reorderMap"/>
+              </tr:commandLink>
+            </tr:panelGroupLayout>
+          </f:facet>
+          <tr:panelGroupLayout layout="scroll"
+                               partialTriggers="reorderMapLink reorderCollectionModelLink">
+            <tr:switcher defaultFacet="home" facetName="#{forEachBean.currentExample}">
+              <f:facet name="home">
+                <tr:outputText value="Choose an example from the side panel."/>
+              </f:facet>
+              <f:facet name="reorderMap">
+                <tr:panelGroupLayout layout="vertical">
+                  <f:subview id="rm">
+                    <jsp:include page="forEach/reorderMap.jspx"/>
+                  </f:subview>
+                </tr:panelGroupLayout>
+              </f:facet>
+              <f:facet name="reorderCollectionModel">
+                <tr:panelGroupLayout layout="vertical">
+                  <f:subview id="rcm">
+                    <jsp:include page="forEach/reorder.jspx"/>
+                  </f:subview>
                 </tr:panelGroupLayout>
-              </tr:panelGroupLayout>
-              <tr:panelFormLayout>
-                <tr:selectOneRadio label="Property:" value="#{forEachBean.sortProperty}">
-                  <tr:selectItem label="(none)" value="#{null}" />
-                  <tr:selectItem label="First name" value="firstName" />
-                  <tr:selectItem label="Last name" value="lastName" />
-                </tr:selectOneRadio>
-                <tr:selectOneRadio label="Order:" value="#{forEachBean.sortAscending}">
-                  <tr:selectItem label="Ascending" value="#{true}" />
-                  <tr:selectItem label="Descending" value="#{false}" />
-                </tr:selectOneRadio>
-                <f:facet name="footer">
-                  <tr:commandLink id="applySort"
-                                  text="Apply sort"
-                                  partialSubmit="true"
-                                  actionListener="#{forEachBean.updateSortOrder}"/>
-                </f:facet>
-              </tr:panelFormLayout>
-            </tr:panelHeader>
-            <tr:commandButton text="Refresh" partialSubmit="true" id="refreshButton"
-                              shortDesc="Test PPR of the for each loop by refreshing the page content"/>
+              </f:facet>
+            </tr:switcher>
           </tr:panelGroupLayout>
-        </tr:panelGroupLayout>
+        </tr:panelBorderLayout>
       </tr:form>
     </tr:document>
   </f:view>

Added: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorder.jspx
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorder.jspx?rev=1389453&view=auto
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorder.jspx (added)
+++ myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorder.jspx Mon Sep 24 16:02:26 2012
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core"
+          xmlns:tr="http://myfaces.apache.org/trinidad" version="2.1">
+  <tr:panelHeader text="Reorder example with CollectionModel">
+    <tr:panelGroupLayout layout="vertical">
+      <f:facet name="separator">
+        <tr:spacer height="1em"/>
+      </f:facet>
+      <tr:outputText value="This example shows the how a for each tag may be backed by a collection
+                            model to permit reordering of components in JSP while retaining
+                            component state with the item in the for each loop instead of the
+                            index." />
+      <tr:outputText value="Normally, in a JSTL for each loop, the components are mapped to the
+                            index of a for each loop. By using keys from a collection model, the
+                            Trinidad for each loop is able to tie the components to the key of an
+                            item in the collection rather than the index. This allows the items
+                            to be reordered and have the component state stay with the object." />
+      <tr:outputText value="Note that the components must be reordered in the parent's children
+                            list as well. Otherwise, the component state will be correct, but
+                            the component will render in the wrong location." />
+      <tr:outputText value="Try disclosing an item in the list below and then change the sorting.
+                            The disclosure state should stay with the item and not with the index,
+                            so if you disclose the show detail in 'Alice Jones', then her
+                            disclosure should remain disclosed during sorting." />
+    </tr:panelGroupLayout>
+    <tr:panelGroupLayout layout="vertical" inlineStyle="padding-left: 2em; padding-top: 1em">
+      <tr:panelHeader text="Components built from the for each loop">
+        <tr:panelGroupLayout layout="vertical" id="personForEachParent"
+                             partialTriggers="applySort"
+                             inlineStyle="padding-bottom: 1em">
+          <tr:forEach var="person" items="#{forEachBean.model}" varStatus="vs">
+            <tr:panelGroupLayout id="personPgl">
+              <f:facet name="separator">
+                <tr:spacer width="10"/>
+              </f:facet>
+              <tr:outputText id="firstName"
+                             value="First name: #{person.firstName}"/>
+              <tr:outputText id="lastName"
+                             value="Last name: #{person.lastName}"/>
+              <tr:outputText id="clientId"
+                             value="(Panel group layout client ID: #{component.parent.clientId})"/>
+            </tr:panelGroupLayout>
+            <tr:showDetail id="showDisclosure" disclosed="false" disclosedText="Disclosed text"
+                           undisclosedText="Undisclosed text">
+              <tr:outputText value="The disclosed state of this text should stay with the item
+                                    during sorting, not with the index."
+                             inlineStyle="padding-left: 1em"/>
+            </tr:showDetail>
+            <tr:separator id="sep1" rendered="#{not vs.last}" />
+          </tr:forEach>
+        </tr:panelGroupLayout>
+      </tr:panelHeader>
+    </tr:panelGroupLayout>
+    <tr:panelHeader text="Sorting options">
+      <tr:panelFormLayout>
+        <tr:selectOneRadio label="Property:" value="#{forEachBean.sortProperty}">
+          <tr:selectItem label="(none)" value="#{null}" />
+          <tr:selectItem label="First name" value="firstName" />
+          <tr:selectItem label="Last name" value="lastName" />
+        </tr:selectOneRadio>
+        <tr:selectOneRadio label="Order:" value="#{forEachBean.sortAscending}">
+          <tr:selectItem label="Ascending" value="#{true}" />
+          <tr:selectItem label="Descending" value="#{false}" />
+        </tr:selectOneRadio>
+        <f:facet name="footer">
+          <tr:commandLink id="applySort"
+                          text="Apply sort"
+                          partialSubmit="true"
+                          actionListener="#{forEachBean.updateSortOrder}"/>
+        </f:facet>
+      </tr:panelFormLayout>
+    </tr:panelHeader>
+  </tr:panelHeader>
+</jsp:root>
\ No newline at end of file

Propchange: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorder.jspx
------------------------------------------------------------------------------
    svn:eol-style = native

Added: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorderMap.jspx
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorderMap.jspx?rev=1389453&view=auto
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorderMap.jspx (added)
+++ myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorderMap.jspx Mon Sep 24 16:02:26 2012
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core"
+          xmlns:tr="http://myfaces.apache.org/trinidad" version="2.1">
+  <tr:panelHeader text="Reorder example with map">
+    <tr:panelGroupLayout layout="vertical">
+      <f:facet name="separator">
+        <tr:spacer height="1em"/>
+      </f:facet>
+      <tr:outputText value="This example shows the how a for each tag may be backed by a map
+                            to permit reordering of components in JSP while retaining
+                            component state with the item in the for each loop instead of the
+                            index." />
+      <tr:outputText value="Normally, in a JSTL for each loop, the components are mapped to the
+                            index of a for each loop. By using keys from a java map, the
+                            Trinidad for each loop is able to tie the components to the key of an
+                            item in the collection rather than the index. This allows the items
+                            to be reordered and have the component state stay with the object." />
+      <tr:outputText value="Note that the components must be reordered in the parent's children
+                            list as well. Otherwise, the component state will be correct, but
+                            the component will render in the wrong location. Also, the map
+                            must keep its iteration order constant. For example, it is
+                            recommended to use a LinkedHashMap instead of a HashMap so that
+                            the order of iteration is maintained." />
+      <tr:outputText value="Try disclosing an item in the list below and then change the sorting.
+                            The disclosure state should stay with the item and not with the index,
+                            so if you disclose the show detail in 'Alice Jones', then her
+                            disclosure should remain disclosed during sorting." />
+    </tr:panelGroupLayout>
+    <tr:panelGroupLayout layout="vertical" inlineStyle="padding-left: 2em; padding-top: 1em">
+      <tr:panelHeader text="Components built from the for each loop">
+        <tr:panelGroupLayout layout="vertical" id="personForEachParent"
+                             partialTriggers="applySort"
+                             inlineStyle="padding-bottom: 1em">
+          <tr:forEach var="person" items="#{forEachBean.map}" varStatus="vs">
+            <tr:panelGroupLayout id="personPgl">
+              <f:facet name="separator">
+                <tr:spacer width="10"/>
+              </f:facet>
+              <tr:outputText id="firstName"
+                             value="First name: #{person.firstName}"/>
+              <tr:outputText id="lastName"
+                             value="Last name: #{person.lastName}"/>
+              <tr:outputText id="clientId"
+                             value="(Panel group layout client ID: #{component.parent.clientId}) Vs: #{empty vs}"/>
+            </tr:panelGroupLayout>
+            <tr:showDetail id="showDisclosure" disclosed="false" disclosedText="Disclosed text"
+                           undisclosedText="Undisclosed text">
+              <tr:outputText value="The disclosed state of this text should stay with the item
+                                    during sorting, not with the index."
+                             inlineStyle="padding-left: 1em"/>
+            </tr:showDetail>
+            <tr:separator id="sep1" rendered="#{not vs.last}" />
+          </tr:forEach>
+        </tr:panelGroupLayout>
+      </tr:panelHeader>
+    </tr:panelGroupLayout>
+    <tr:panelHeader text="Sorting options">
+      <tr:panelFormLayout>
+        <tr:selectOneRadio label="Property:" value="#{forEachBean.sortProperty}">
+          <tr:selectItem label="(none)" value="#{null}" />
+          <tr:selectItem label="First name" value="firstName" />
+          <tr:selectItem label="Last name" value="lastName" />
+        </tr:selectOneRadio>
+        <tr:selectOneRadio label="Order:" value="#{forEachBean.sortAscending}">
+          <tr:selectItem label="Ascending" value="#{true}" />
+          <tr:selectItem label="Descending" value="#{false}" />
+        </tr:selectOneRadio>
+        <f:facet name="footer">
+          <tr:commandLink id="applySort"
+                          text="Apply sort"
+                          partialSubmit="true"
+                          actionListener="#{forEachBean.updateSortOrder}"/>
+        </f:facet>
+      </tr:panelFormLayout>
+    </tr:panelHeader>
+  </tr:panelHeader>
+</jsp:root>
\ No newline at end of file

Propchange: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach/reorderMap.jspx
------------------------------------------------------------------------------
    svn:eol-style = native

Added: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach2.jspx
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach2.jspx?rev=1389453&view=auto
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach2.jspx (added)
+++ myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach2.jspx Mon Sep 24 16:02:26 2012
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core"
+          xmlns:tr="http://myfaces.apache.org/trinidad" version="1.2">
+  <jsp:directive.page contentType="text/html;charset=utf-8"/>
+  <f:view>
+    <tr:document title="ForEach Demo">
+      <tr:form>
+        <tr:panelGroupLayout layout="vertical" partialTriggers="refreshButton">
+          <f:facet name="separator">
+            <tr:separator/>
+          </f:facet>
+          <tr:navigationPane hint="buttons">
+            <tr:commandNavigationItem immediate="true" text="Component Guide" action="guide"/>
+            <tr:commandNavigationItem immediate="true"
+                                      destination="http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_forEach.html"
+                                      text="Tag Documentation"/>
+          </tr:navigationPane>
+          <tr:goLink destination="http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_breadCrumbs.html"
+                     text="Tag Documentation"/>
+          <tr:outputFormatted styleUsage="instruction" value="&lt;b>forEach&lt;/b>"/>
+          <tr:panelGroupLayout layout="vertical">
+            <f:facet name="separator">
+              <tr:spacer height="12" />
+            </f:facet>
+            <tr:panelHeader text="Simple for each loop, no items">
+              <tr:panelGroupLayout layout="vertical">
+                <tr:forEach var="item" begin="0" end="2">
+                  <tr:outputText id="outputText" value="Client ID: #{component.clientId}"/>
+                </tr:forEach>
+              </tr:panelGroupLayout>
+            </tr:panelHeader>
+            <tr:panelHeader text="Simple for each loop, items from list">
+              <tr:panelGroupLayout layout="vertical">
+                <tr:forEach var="item" items="#{forEachBean.simpleList}">
+                  <tr:outputText id="outputText1" value="Client ID: #{component.clientId}"/>
+                </tr:forEach>
+              </tr:panelGroupLayout>
+            </tr:panelHeader>
+            <tr:panelHeader text="Simple for each loop, items from list, fixed IDs">
+              <tr:panelGroupLayout layout="vertical">
+                <tr:forEach var="item" items="#{forEachBean.simpleList}" varStatus="vs">
+                  <tr:outputText id="outputText2_${vs.key}"
+                                 value="Client ID: #{component.clientId}. Text: #{item}"/>
+                </tr:forEach>
+              </tr:panelGroupLayout>
+            </tr:panelHeader>
+            <tr:panelHeader text="Var status properties with list items">
+              <tr:panelGroupLayout layout="vertical">
+                <tr:forEach var="item" items="#{forEachBean.simpleList}" varStatus="vs">
+                  <tr:panelGroupLayout>
+                    <f:facet name="separator">
+                      <tr:spacer width="10"/>
+                    </f:facet>
+                    <tr:outputText value="Index: #{vs.index}"/>
+                    <tr:outputText value="Count: #{vs.count}"/>
+                    <tr:outputText value="Key: #{vs.key}"/>
+                    <tr:outputText value="First: #{vs.first}"/>
+                    <tr:outputText value="Last: #{vs.last}"/>
+                  </tr:panelGroupLayout>
+                  <tr:separator rendered="#{not vs.last}" />
+                </tr:forEach>
+              </tr:panelGroupLayout>
+            </tr:panelHeader>
+            <tr:panelHeader text="Reorder example with CollectionModel">
+              <tr:panelGroupLayout layout="vertical">
+                <tr:panelGroupLayout layout="vertical" id="personForEachParent"
+                                     partialTriggers="applySort">
+                  <tr:forEach var="person" items="#{forEachBean.model}" varStatus="vs">
+                    <tr:panelGroupLayout id="personPgl">
+                      <f:facet name="separator">
+                        <tr:spacer width="10"/>
+                      </f:facet>
+                      <tr:outputText id="firstName"
+                                     value="First name: #{person.firstName}"/>
+                      <tr:outputText id="lastName"
+                                     value="Last name: #{person.lastName}"/>
+                      <tr:outputText id="clientId"
+                                     value="(Panel group layout client ID: #{component.parent.clientId})"/>
+                    </tr:panelGroupLayout>
+                    <tr:separator id="sep1" rendered="#{not vs.last}" />
+                  </tr:forEach>
+                </tr:panelGroupLayout>
+              </tr:panelGroupLayout>
+              <tr:panelFormLayout>
+                <tr:selectOneRadio label="Property:" value="#{forEachBean.sortProperty}">
+                  <tr:selectItem label="(none)" value="#{null}" />
+                  <tr:selectItem label="First name" value="firstName" />
+                  <tr:selectItem label="Last name" value="lastName" />
+                </tr:selectOneRadio>
+                <tr:selectOneRadio label="Order:" value="#{forEachBean.sortAscending}">
+                  <tr:selectItem label="Ascending" value="#{true}" />
+                  <tr:selectItem label="Descending" value="#{false}" />
+                </tr:selectOneRadio>
+                <f:facet name="footer">
+                  <tr:commandLink id="applySort"
+                                  text="Apply sort"
+                                  partialSubmit="true"
+                                  actionListener="#{forEachBean.updateSortOrder}"/>
+                </f:facet>
+              </tr:panelFormLayout>
+            </tr:panelHeader>
+            <tr:commandButton text="Refresh" partialSubmit="true" id="refreshButton"
+                              shortDesc="Test PPR of the for each loop by refreshing the page content"/>
+          </tr:panelGroupLayout>
+        </tr:panelGroupLayout>
+      </tr:form>
+    </tr:document>
+  </f:view>
+</jsp:root>

Propchange: myfaces/trinidad/branches/ar_1940/trinidad-examples/trinidad-demo/src/main/webapp/demos/tags/forEach2.jspx
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java?rev=1389453&r1=1389452&r2=1389453&view=diff
==============================================================================
--- myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java (original)
+++ myfaces/trinidad/branches/ar_1940/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/taglib/ForEachTag.java Mon Sep 24 16:02:26 2012
@@ -22,10 +22,13 @@ import java.io.Serializable;
 
 import java.lang.reflect.Array;
 
+import java.util.Collections;
 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.el.ELContext;
 import javax.el.PropertyNotWritableException;
@@ -41,6 +44,7 @@ import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.JspTagException;
 import javax.servlet.jsp.tagext.JspIdConsumer;
 
+import org.apache.myfaces.trinidad.component.UIXComponent;
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
 import org.apache.myfaces.trinidad.model.CollectionModel;
 import org.apache.myfaces.trinidad.webapp.TrinidadIterationTag;
@@ -251,6 +255,10 @@ public class ForEachTag
 
     _parentComponent = _getParentComponent();
 
+    // Remember the non-Trinidad components before execution so that we may determine which
+    // are created during this tags for each execution
+    _previousIterationNonTrinidadChildren = _getNonTrinidadChildren();
+
     _updateVars(true);
 
     return EVAL_BODY_INCLUDE;
@@ -260,6 +268,10 @@ public class ForEachTag
   public int doAfterBody()
   {
     _LOG.finest("doAfterBody processing");
+
+    // Process any non-Trinidad components that were added during the last body execution
+    _processNonTrinidadComponents();
+
     _currentIndex += _currentStep;
     ++_currentCount;
     _isFirst = false;
@@ -279,6 +291,7 @@ public class ForEachTag
       {
         popComponentSuffix();
         _suffixPushed = false;
+        _previousIterationNonTrinidadChildren = null;
       }
 
       return SKIP_BODY;
@@ -314,6 +327,8 @@ public class ForEachTag
     _iterationMap = null;
     _itemsWrapper = null;
 
+    _previousIterationNonTrinidadChildren = null;
+
     _parentComponent = null;
 
     _suffixPushed = false;
@@ -370,7 +385,7 @@ public class ForEachTag
   }
 
   @Override
-  public void afterChildComponentProcessed(
+  public final void afterChildComponentProcessed(
     UIComponent component)
   {
     // This code is called when a component is created or found, see which it is.
@@ -395,6 +410,27 @@ public class ForEachTag
     }
   }
 
+  private Set<UIComponent> _getNonTrinidadChildren()
+  {
+    if (_parentComponent == null)
+    {
+      return Collections.emptySet();
+    }
+
+    Set<UIComponent> components = new HashSet<UIComponent>(_parentComponent.getChildCount());
+    for (UIComponent child : _parentComponent.getChildren())
+    {
+      if (child instanceof UIXComponent)
+      {
+        continue;
+      }
+
+      components.add(child);
+    }
+
+    return components;
+  }
+
   private UIComponent _getParentComponent()
   {
     UIComponentClassicTagBase tag = UIComponentClassicTagBase.getParentUIComponentClassicTagBase(
@@ -402,11 +438,101 @@ public class ForEachTag
     return tag == null ? null : tag.getComponentInstance();
   }
 
+  /**
+   * Get the key for the current item in the items. For non-key based collections, this is the
+   * index. If there is no items attribute, this simply returns the current index as well.
+   *
+   * @return the key or index
+   */
+  private Serializable _getKey()
+  {
+    return (_itemsWrapper == null) ?
+      _currentIndex :
+      _asSerializable(_itemsWrapper.getKey(_currentIndex));
+  }
+
+  /**
+   * Although in-efficient in how we process UIXComponent children, this function allows
+   * non-Trinidad components to correctly map their value expressions to the iteration of the
+   * for each loop better than the JSTL tag does in JSF. In order to do this, this function must
+   * determine what non-UIXComponents belong to the current iteration of the loop.
+   *
+   * @see #afterChildComponentProcessed(UIComponent)
+   * @see #childComponentProcessed(UIComponent)
+   */
+  private void _processNonTrinidadComponents()
+  {
+    Serializable key = null;
+
+    // If _previousIterationNonTrinidadChildren is non-null then this is not the first
+    // execution of this code in this request. We need to determine what components were added
+    // during this iteration
+    Set<UIComponent> childrenComponents = _getNonTrinidadChildren();
+    if (childrenComponents.isEmpty())
+    {
+      _previousIterationNonTrinidadChildren.clear();
+      return;
+    }
+
+    for (UIComponent child : childrenComponents)
+    {
+      Map<String, Object> attrs = child.getAttributes();
+      if (_previousIterationNonTrinidadChildren.contains(child))
+      {
+        // This child component is either one that was created in a previous request, or
+        // one that was not created by this for each loop, we need to determine which one.
+        NonTrinidadIterationData data = (NonTrinidadIterationData)attrs.get(_iterationMapKey);
+
+        // If the data is null, then this for each tag did not create the component and we
+        // do not need to do anything.
+        if (data == null)
+        {
+          continue;
+        }
+
+        // Get the key for the current item, if we have not already
+        if (key == null)
+        {
+          key = _getKey();
+        }
+
+        // Since we clear the iteration map in the start tag processing, we need to re-map
+        // the iteration ID from the component back to the current iteration data.
+        // First, we need to ensure that this component belongs to the current iteration. If
+        // it doesn't, we do not need to do anything as the component "belongs" to a different
+        // iteration
+        if (key.equals(data.getKey()))
+        {
+          // The keys are the same, update the map.
+          _iterationMap.put(data.getIterationId(), _iterationData);
+        }
+      }
+      else
+      {
+        // This is a component that was added to the parent while this for each loop was processing
+        // the last iteration. We need to record the key and the iteration ID so that we can map
+        // this component to its var status
+
+        // Get the key for the current item, if we have not already
+        if (key == null)
+        {
+          key = _getKey();
+        }
+
+        attrs.put(_iterationMapKey, new NonTrinidadIterationData(key, _iterationId));
+      }
+    }
+
+    // Update the map so we know for the next iteration what components are being created
+    _previousIterationNonTrinidadChildren = childrenComponents;
+  }
+
   // Push new values into the VariableMapper and the pageContext
   private void _updateVars(
     boolean createNewIterationData)
   {
     VariableMapper vm = pageContext.getELContext().getVariableMapper();
+    Serializable   key = null;
 
     // Generate a new iteration ID
     _updateIterationId();
@@ -422,13 +548,14 @@ public class ForEachTag
         if (_itemsWrapper.isKeyBased())
         {
           // Use a key to get the value
-          Serializable key = _asSerializable(_itemsWrapper.getKey(_currentIndex));
-          expr = new KeyedValueExpression(_items, key);
+          key = _getKey();
+          expr = new KeyedValueExpression(_items, _getKey());
         }
         else
         {
           // Use indirection to get the index from the iteration data using the iteration ID
-          // so that the expression is not hard-coded to one index
+          // so that the expression is not hard-coded to one index. This allows the tag to
+          // support components that are re-ordered (index changes during multiple requests)
           expr = new IndexedValueExpression(_iterationId, _iterationMapKey, _items);
         }
 
@@ -445,17 +572,14 @@ public class ForEachTag
       }
     }
 
-    Object key = _itemsWrapper == null ?
-      _currentIndex : _itemsWrapper.getKey(_currentIndex);
-
-    if (!(key instanceof Serializable))
-    {
-      throw new IllegalStateException("For each loop keys must be serializable");
-    }
-
     if (createNewIterationData || _iterationData == null)
     {
-      _iterationData = new IterationMetaData((Serializable)key, _isFirst, _isLast,
+      if (key == null)
+      {
+        key = _getKey();
+      }
+
+      _iterationData = new IterationMetaData(key, _isFirst, _isLast,
                          _currentBegin, _currentCount, _currentIndex, _currentEnd);
     }
 
@@ -495,9 +619,22 @@ public class ForEachTag
     // To do, support non-key pass-through
     if (_itemsWrapper != null && _itemsWrapper.isIdSuffixSupported())
     {
+      if (key == null)
+      {
+        key = _getKey();
+      }
+
       pushComponentSuffix("_" + key.toString());
       _suffixPushed = true;
     }
+
+    if (_previousIterationNonTrinidadChildren == null)
+    {
+      // If _previousIterationNonTrinidadChildren is null, then this is the first execution
+      // of this function for this tag in this request, store off the non-Trinidad children
+      // components so that we can attempt to determine the ones that are added
+      _previousIterationNonTrinidadChildren = _getNonTrinidadChildren();
+    }
   }
 
   private Integer _evaluateInteger(
@@ -964,7 +1101,7 @@ public class ForEachTag
         return;
       }
 
-      if (index < _currentIndex)
+      if (_iter == null || index < _currentIndex)
       {
         // Need to re-create the iterator
         _iter = _map.entrySet().iterator();
@@ -1154,6 +1291,31 @@ public class ForEachTag
     private Serializable _key;
   }
 
+  private static class NonTrinidadIterationData
+    implements Serializable
+  {
+    public NonTrinidadIterationData(
+      Serializable key,
+      Integer      iterationId)
+    {
+      _key = key;
+      _iterationId = iterationId;
+    }
+
+    public Serializable getKey()
+    {
+      return _key;
+    }
+
+    public Integer getIterationId()
+    {
+      return _iterationId;
+    }
+
+    private final Serializable _key;
+    private final Integer      _iterationId;
+  }
+
   private int _currentBegin;
   private int _currentIndex;
   private int _currentEnd;
@@ -1176,6 +1338,8 @@ public class ForEachTag
 
   private UIComponent _parentComponent;
 
+  private Set<UIComponent> _previousIterationNonTrinidadChildren;
+
   private Integer _iterationId;
   private IterationMetaData _iterationData;
   private Map<String, Object> _viewAttributes;
@@ -1192,7 +1356,22 @@ public class ForEachTag
   private ValueExpression _previousDeferredVarStatus;
 
   private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(ForEachTag.class);
-  private static final String _VIEW_ATTR_KEY = ForEachTag.class.getName() + ".";
+
+  /**
+   * Due to the fact that JSP tag IDs may be reused in different JSP files, we must differentiate
+   * tags by not only their JSP IDs, but also a unique number per inc
+   */
+  private static final String JAVAX_FACES_PAGECONTEXT_MARKER =
+          "javax.faces.webapp.PAGECONTEXT_MARKER";
+
+  /**
+   * This is a <code>facesContext</code> scoped attribute which contains
+   * an AtomicInteger which we use to increment the PageContext
+   * count.
+   */
+  private static final String JAVAX_FACES_PAGECONTEXT_COUNTER =
+          "javax.faces.webapp.PAGECONTEXT_COUNTER";
+
   private static final int _VIEW_ATTR_KEY_LENGTH = _VIEW_ATTR_KEY.length();
   private static final String _ITERATION_ID_KEY =
     ForEachTag.class.getName() + ".ITER";