You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2007/10/13 23:13:06 UTC

svn commit: r584454 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/internal/services/ main/resources/org/apache/tapestry/internal/services/ site/apt/guide/ test/java/org/apache/tapestry/internal/services/ test/resources...

Author: hlship
Date: Sat Oct 13 14:13:05 2007
New Revision: 584454

URL: http://svn.apache.org/viewvc?rev=584454&view=rev
Log:
TAPESTRY-1469: Templates should support an outer t:container element for when a template consists of non-tree structured content

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/container_element.tml
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/tapestry_5_0_0.xsd
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/templates.apt
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java?rev=584454&r1=584453&r2=584454&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java Sat Oct 13 14:13:05 2007
@@ -47,6 +47,7 @@
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
 import org.apache.tapestry.ioc.internal.util.LocationImpl;
 import org.apache.tapestry.ioc.internal.util.TapestryException;
+import org.apache.tapestry.ioc.util.Stack;
 import org.slf4j.Logger;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
@@ -82,13 +83,13 @@
 
     private final List<TemplateToken> _tokens = newList();
 
-    // Non-blank ids from start component (<comp>) elements
+    // Non-blank ids from start component elements
 
     private final Set<String> _componentIds = newSet();
 
-    // Used to accumulate text provided by the characters(). Even contiguous characters may be
-    // broken up across multiple invocations due to parser internals. We accumulate those together
-    // before forming a text token.
+    // Used to accumulate text provided by the characters() method. Even contiguous characters may
+    // be broken up across multiple invocations due to parser internals. We accumulate those
+    // together before forming a text token.
 
     private final StringBuilder _textBuffer = new StringBuilder();
 
@@ -106,6 +107,23 @@
 
     private final Map<String, URL> _configuration;
 
+    private final Stack<Runnable> _endTagHandlerStack = new Stack<Runnable>();
+
+    private final Runnable _addEndElementToken = new Runnable()
+    {
+        public void run()
+        {
+            _tokens.add(new EndElementToken(getCurrentLocation()));
+        }
+    };
+
+    private final Runnable _ignoreEndElement = new Runnable()
+    {
+        public void run()
+        {
+        }
+    };
+
     // Note the use of the non-greedy modifier; this prevents the pattern from merging multiple
     // expansions on the same text line into a single large
     // but invalid expansion.
@@ -134,6 +152,11 @@
         _insideBody = false;
         _insideBodyErrorLogged = false;
         _ignoreEvents = true;
+
+        // Stack needs a clear();
+
+        while (!_endTagHandlerStack.isEmpty())
+            _endTagHandlerStack.pop();
     }
 
     public ComponentTemplate parseTemplate(Resource templateResource)
@@ -338,6 +361,12 @@
             return;
         }
 
+        if (localName.equalsIgnoreCase("container"))
+        {
+            startContainer();
+            return;
+        }
+
         // The component type is derived from the element name. Since element names may not contain
         // slashes, we convert periods to slashes. Later down the pipeline, they'll probably be
         // converted back into periods, as part of a fully qualified class name.
@@ -348,6 +377,12 @@
         startPossibleComponent(attributes, null, componentType);
     }
 
+    private void startContainer()
+    {
+        // Neither the container nor its end tag are considered tokens, just the contents inside.
+        _endTagHandlerStack.push(_ignoreEndElement);
+    }
+
     private void startBlock(Attributes attributes)
     {
         String blockId = findSingleParameter("block", "id", attributes);
@@ -355,6 +390,7 @@
         // null is ok for blockId
 
         _tokens.add(new BlockToken(blockId, getCurrentLocation()));
+        _endTagHandlerStack.push(_addEndElementToken);
     }
 
     private void startParameter(Attributes attributes)
@@ -366,6 +402,7 @@
                     getCurrentLocation(), null);
 
         _tokens.add(new ParameterToken(parameterName, getCurrentLocation()));
+        _endTagHandlerStack.push(_addEndElementToken);
     }
 
     private String findSingleParameter(String elementName, String attributeName,
@@ -478,6 +515,11 @@
         _tokens.addAll(attributeTokens);
 
         if (id != null) _componentIds.add(id);
+
+        // TODO: Is there value in having different end elements for components vs. ordinary
+        // elements?
+
+        _endTagHandlerStack.push(_addEndElementToken);
     }
 
     private void startBody()
@@ -486,20 +528,23 @@
 
         _insideBody = true;
         _insideBodyErrorLogged = false;
+
+        _endTagHandlerStack.push(new Runnable()
+        {
+            public void run()
+            {
+                _insideBody = false;
+
+                // And don't add an end element token.
+            }
+        });
     }
 
     public void endElement(String uri, String localName, String qName) throws SAXException
     {
         processTextBuffer();
 
-        // TODO: Handle tapestry namespace elements?
-
-        // Because XML tags are always balanced, we don't even need to know what element just closed
-        // when we assemble things later.
-
-        if (!_insideBody) _tokens.add(new EndElementToken(getCurrentLocation()));
-
-        _insideBody = false;
+        _endTagHandlerStack.pop().run();
     }
 
     private Location getCurrentLocation()

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/tapestry_5_0_0.xsd
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/tapestry_5_0_0.xsd?rev=584454&r1=584453&r2=584454&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/tapestry_5_0_0.xsd (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/services/tapestry_5_0_0.xsd Sat Oct 13 14:13:05 2007
@@ -2,7 +2,6 @@
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
     xmlns="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"
     targetNamespace="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">    
-    <!-- body identifies where the body of the component belongs within the component's template -->
     <xs:element name="body">
         <xs:annotation>
             <xs:documentation>
@@ -11,6 +10,14 @@
                 their body within their template.
             </xs:documentation>
         </xs:annotation>
+    </xs:element>
+    <xs:element name="container">
+      <xs:annotation>
+        <xs:documentation>
+          May be used as the root element of a template, but is not part of the template itself. Useful when
+          a component exists to emit a series of related elements that are not inside a containing element.
+        </xs:documentation>
+      </xs:annotation>
     </xs:element>
     <xs:element name="parameter">
         <xs:annotation>

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/templates.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/templates.apt?rev=584454&r1=584453&r2=584454&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/templates.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/templates.apt Sat Oct 13 14:13:05 2007
@@ -161,6 +161,23 @@
    Tapestry 4 users will recognize the \<body\> element as a replacement for the
    RenderBody component.
    
+* \<container\>
+
+   A container element contains markup without being considered part of the template. This is useful for components that render several top level
+   tags, for example, a component that renders several columns within a table row:
+   
++---+
+<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+  <td>${label}</td>
+  <td>${value}</td>
+</t:container>
++---+     
+   
+   This component only makes sense when used inside a \<tr\> element of its container's template.
+   
+   Without the \<t:container\> element, there would be no way to create a valid XML document as the template, because XML documents must always
+   have a single root element.
+   
 * \<block\>
 
   A block is a container of a portion of the component template. A block does not normally render; any component or contents you put inside

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java?rev=584454&r1=584453&r2=584454&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/TemplateParserImplTest.java Sat Oct 13 14:13:05 2007
@@ -96,7 +96,7 @@
     }
 
     @Test
-    synchronized void just_HTML()
+    synchronized public void just_HTML()
     {
         Resource resource = getResource("justHTML.tml");
 
@@ -147,7 +147,31 @@
     }
 
     @Test
-    void xml_entity()
+    public void container_element()
+    {
+        List<TemplateToken> tokens = tokens("container_element.tml");
+
+        assertEquals(tokens.size(), 4);
+
+        TextToken t0 = get(tokens, 0);
+
+        assertEquals(t0.getText().trim(), "A bit of text.");
+
+        StartElementToken t1 = get(tokens, 1);
+
+        assertEquals(t1.getName(), "foo");
+
+        EndElementToken t2 = get(tokens, 2);
+
+        assertNotNull(t2); // Keep compiler happy
+
+        TextToken t3 = get(tokens, 3);
+
+        assertEquals(t3.getText().trim(), "Some more text.");
+    }
+
+    @Test
+    public void xml_entity()
     {
         List<TemplateToken> tokens = tokens("xmlEntity.tml");
 
@@ -163,7 +187,7 @@
 
     /** Test disabled when not online. */
     @Test(enabled = false)
-    void html_entity()
+    public void html_entity()
     {
         List<TemplateToken> tokens = tokens("html_entity.tml");
 
@@ -182,7 +206,7 @@
     }
 
     @Test
-    void cdata()
+    public void cdata()
     {
         List<TemplateToken> tokens = tokens("cdata.tml");
 
@@ -197,7 +221,7 @@
     }
 
     @Test
-    void comment()
+    public void comment()
     {
         List<TemplateToken> tokens = tokens("comment.tml");
 
@@ -215,7 +239,7 @@
     }
 
     @Test
-    void multiline_comment()
+    public void multiline_comment()
     {
         List<TemplateToken> tokens = tokens("multilineComment.tml");
 
@@ -231,7 +255,7 @@
     }
 
     @Test
-    void component()
+    public void component()
     {
         List<TemplateToken> tokens = tokens("component.tml");
 
@@ -247,7 +271,7 @@
     }
 
     @Test
-    void component_with_body()
+    public void component_with_body()
     {
         List<TemplateToken> tokens = tokens("componentWithBody.tml");
 
@@ -308,7 +332,7 @@
     }
 
     @Test
-    void body_element()
+    public void body_element()
     {
         List<TemplateToken> tokens = tokens("body_element.tml");
 
@@ -321,7 +345,7 @@
     }
 
     @Test
-    void content_within_body_element()
+    public void content_within_body_element()
     {
         List<TemplateToken> tokens = parse("content_within_body_element.tml").getTokens();
 
@@ -336,7 +360,7 @@
     }
 
     @Test
-    void component_with_parameters()
+    public void component_with_parameters()
     {
         List<TemplateToken> tokens = tokens("componentWithParameters.tml");
 

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/container_element.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/container_element.tml?rev=584454&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/container_element.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/container_element.tml Sat Oct 13 14:13:05 2007
@@ -0,0 +1,9 @@
+<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+A bit of text.
+
+<foo/>
+
+Some more text.
+
+</t:container>