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 2012/02/17 01:28:43 UTC

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

Author: hlship
Date: Fri Feb 17 00:28:42 2012
New Revision: 1245264

URL: http://svn.apache.org/viewvc?rev=1245264&view=rev
Log:
TAP5-1847: An extension component template (with a root t:extend element) should allow t:block elements to be nested

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/tapestry_5_4.xsd
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/block_can_nest_inside_extend.tml
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java?rev=1245264&r1=1245263&r2=1245264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/SaxTemplateParser.java Fri Feb 17 00:28:42 2012
@@ -1,4 +1,4 @@
-// Copyright 2009, 2011 The Apache Software Foundation
+// Copyright 2009, 2011, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -60,7 +60,13 @@ public class SaxTemplateParser
     {
         NAMESPACE_URI_TO_VERSION.put("http://tapestry.apache.org/schema/tapestry_5_0_0.xsd", T_5_0);
         NAMESPACE_URI_TO_VERSION.put("http://tapestry.apache.org/schema/tapestry_5_1_0.xsd", T_5_1);
+        // 5.2 didn't change the schmea, so the 5_1_0.xsd was still used.
+        // 5.3 fixes an incorrect element name in the XSD ("replacement" should be "replace")
+        // The parser code here always expected "replace".
         NAMESPACE_URI_TO_VERSION.put("http://tapestry.apache.org/schema/tapestry_5_3.xsd", T_5_3);
+        // 5.4 is pretty much the same as 5.3, but allows block inside extend
+        // as per TAP5-1847
+        NAMESPACE_URI_TO_VERSION.put("http://tapestry.apache.org/schema/tapestry_5_4.xsd", T_5_4);
     }
 
     /**
@@ -212,7 +218,7 @@ public class SaxTemplateParser
         String name = tokenStream.getLocalName();
         Version version = NAMESPACE_URI_TO_VERSION.get(uri);
 
-        if (T_5_1.before(version))
+        if (T_5_1.sameOrEarlier(version))
         {
             if (name.equalsIgnoreCase("extend"))
             {
@@ -243,26 +249,36 @@ public class SaxTemplateParser
             {
                 case START_ELEMENT:
 
-                    if (T_5_1.before(NAMESPACE_URI_TO_VERSION.get(tokenStream.getNamespaceURI()))
-                            && tokenStream.getLocalName().equalsIgnoreCase("replace"))
+                    if (isTemplateVersion(Version.T_5_1) && isElementName("replace"))
                     {
                         replace(state);
                         break;
                     }
 
-                    throw new RuntimeException("Child element of <extend> must be <replace>.");
+                    boolean is54 = isTemplateVersion(Version.T_5_4);
+
+                    if (is54 && isElementName("block"))
+                    {
+                        block(state);
+                        break;
+                    }
+
+                    throw new RuntimeException(
+                            is54
+                                    ? "Child element of <extend> must be <replace> or <block>."
+                                    : "Child element of <extend> must be <replace>.");
 
                 case END_ELEMENT:
 
                     return;
 
-                // Ignore spaces and characters inside <extend>.
+                // Ignore spaces and comments directly inside <extend>.
 
                 case COMMENT:
                 case SPACE:
                     break;
 
-                // Other content (characters, etc.) are forbidden.
+                // Other non-whitespace content (characters, etc.) are forbidden.
 
                 case CHARACTERS:
                     if (InternalUtils.isBlank(tokenStream.getText()))
@@ -274,6 +290,24 @@ public class SaxTemplateParser
         }
     }
 
+    /**
+     * Returns true if the <em>local name</em> is the element name (ignoring case).
+     */
+    private boolean isElementName(String elementName)
+    {
+        return tokenStream.getLocalName().equalsIgnoreCase(elementName);
+    }
+
+    /**
+     * Returns true if the template version is at least the required version.
+     */
+    private boolean isTemplateVersion(Version requiredVersion)
+    {
+        Version templateVersion = NAMESPACE_URI_TO_VERSION.get(tokenStream.getNamespaceURI());
+
+        return requiredVersion.sameOrEarlier(templateVersion);
+    }
+
     private void replace(TemplateParserState state)
     {
         String id = getRequiredIdAttribute();
@@ -335,7 +369,7 @@ public class SaxTemplateParser
         String name = tokenStream.getLocalName();
         Version version = NAMESPACE_URI_TO_VERSION.get(uri);
 
-        if (T_5_1.before(version))
+        if (T_5_1.sameOrEarlier(version))
         {
 
             if (name.equalsIgnoreCase("remove"))
@@ -391,7 +425,7 @@ public class SaxTemplateParser
 
             if (name.equalsIgnoreCase("parameter"))
             {
-                if (T_5_3.before(version))
+                if (T_5_3.sameOrEarlier(version))
                 {
                     throw new RuntimeException(
                             String.format("The <parameter> element has been deprecated in Tapestry 5.3 in favour of '%s' namespace.", TAPESTRY_PARAMETERS_URI));
@@ -1168,7 +1202,7 @@ public class SaxTemplateParser
 
     static enum Version
     {
-        T_5_0(5, 0), T_5_1(5, 1), T_5_3(5, 3);
+        T_5_0(5, 0), T_5_1(5, 1), T_5_3(5, 3), T_5_4(5, 4);
 
         private int major;
         private int minor;
@@ -1180,7 +1214,11 @@ public class SaxTemplateParser
             this.minor = minor;
         }
 
-        public boolean before(Version other)
+        /**
+         * Returns true if this Version is the same as, or ordered before the other Version. This is often used to enable new
+         * template features for a specific version.
+         */
+        public boolean sameOrEarlier(Version other)
         {
             if (other == null)
                 return false;

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/tapestry_5_4.xsd
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/tapestry_5_4.xsd?rev=1245264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/tapestry_5_4.xsd (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/tapestry_5_4.xsd Fri Feb 17 00:28:42 2012
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           xmlns="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
+           targetNamespace="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
+    <xs:element name="body">
+        <xs:annotation>
+            <xs:documentation>
+                Defines the position within the template that the body of the component (the portion of the container's
+                template
+                enclosed by the component) will be rendered. This is optional, and only applies to components that wish
+                to render
+                their body within their template.
+            </xs:documentation>
+        </xs:annotation>
+    </xs:element>
+    <xs:element name="extend">
+        <xs:annotation>
+            <xs:documentation>
+                Root element of a template that extends its parent template, replacing portions of the template.
+                extend elemenst may containg replace and block elements.
+            </xs:documentation>
+        </xs:annotation>
+    </xs:element>
+    <xs:element name="extension-point">
+        <xs:annotation>
+            <xs:documentation>
+                Defines a portion of a parent component template that may be replaced in a child component.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:attribute name="name" type="xs:string" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        Unique id for the replaceable block.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="replace">
+        <xs:annotation>
+            <xs:documentation>
+                A replacement, in a child component template, for an extension-point in the parent component template.
+                This element must be an immediate child of the root element, which will be extend.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:attribute name="name" type="xs:string" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        Unique id for the replaceable block, which must match an id of an inheritable extension-point
+                        block.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="content">
+        <xs:annotation>
+            <xs:documentation>
+                Marks a portion of the template as the relevant portion; anything outside of the element is discarded.
+                content elements may not be nested inside other content elements.
+            </xs:documentation>
+        </xs:annotation>
+    </xs:element>
+    <xs:element name="remove">
+        <xs:annotation>
+            <xs:documentation>
+                A block of the template to be removed. This can be used as a comment, or to temporarily
+                delete a portion of the template (including markup, expansions and embedded components).
+            </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="block">
+        <xs:annotation>
+            <xs:documentation>
+                A block is simply a container of other elements. Blocks do not render themselves or their bodies in the
+                normal flow; they
+                only get rendered when specifially directed to.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:attribute name="id" type="xs:ID">
+                <xs:annotation>
+                    <xs:documentation>
+                        An optional identifier that is used to reference the block from inside the Java class.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
+</xs:schema>

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java?rev=1245264&r1=1245263&r2=1245264&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java Fri Feb 17 00:28:42 2012
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -1003,11 +1003,24 @@ public class TemplateParserImplTest exte
     }
 
     @Test
-    public void utf8_template() throws Exception {
+    public void utf8_template() throws Exception
+    {
         List<TemplateToken> tokens = tokens("chinese_utf-8.tml");
 
         TextToken token7 = get(tokens, 7);
 
         assertEquals(token7.text.trim().substring(0, 3), "\u975E\u5e38\u7b80");
     }
+
+    @Test
+    public void block_can_nest_inside_extend() throws Exception
+    {
+        List<TemplateToken> tokens = tokens("block_can_nest_inside_extend.tml");
+
+        System.out.println(tokens);
+        
+        BlockToken token = get(tokens, 0);
+
+        assert (token.getId().equals("myBlock"));
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/block_can_nest_inside_extend.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/block_can_nest_inside_extend.tml?rev=1245264&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/block_can_nest_inside_extend.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/block_can_nest_inside_extend.tml Fri Feb 17 00:28:42 2012
@@ -0,0 +1,5 @@
+<t:extend xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
+    <t:block id="myBlock">
+        Block content
+    </t:block>
+</t:extend>
\ No newline at end of file