You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/10/20 21:09:26 UTC

svn commit: r586776 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/dom/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/internal/test/ main/java/org/apache/t...

Author: hlship
Date: Sat Oct 20 12:09:24 2007
New Revision: 586776

URL: http://svn.apache.org/viewvc?rev=586776&view=rev
Log:
TAPESTRY-1841: Extend PageRenderSupport to have equivalent support for CSS stylesheets

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilder.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImpl.java
      - copied, changed from r585511, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImplTest.java
      - copied, changed from r585511, tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImplTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/add_style_links.txt
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/duplicate_scripts_ignored_first_media_wins.txt
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/existing_head_used_if_present.txt
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/no_body_element.txt
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentScriptBuilder.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommand.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImplTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InjectStandardStylesheetCommandTest.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/PageRenderSupport.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderSupportImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderSupportImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/PageRenderSupport.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/PageRenderSupport.java?rev=586776&r1=586775&r2=586776&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/PageRenderSupport.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/PageRenderSupport.java Sat Oct 20 12:09:24 2007
@@ -21,7 +21,7 @@
 /**
  * Provides support to all components that render. This is primarily about generating unique
  * client-side ids (very important for JavaScript generation) as well as accumulating JavaScript to
- * be sent to the client.
+ * be sent to the client. PageRenderSupport also allows for the incremental addition of stylesheets.
  */
 public interface PageRenderSupport
 {
@@ -56,6 +56,19 @@
      *            converted into an asset.
      */
     void addClasspathScriptLink(String... classpaths);
+
+    /**
+     * Adds a link to a CSS stylesheet. As with JavaScript libraries, each stylesheet is added at
+     * most once. Stylesheets added this way will be ordered before any other content in the
+     * <head> element of the document. The <head> element will be created, if necessary.
+     * 
+     * @param stylesheet
+     *            the asset referencing the stylesheet
+     * @param media
+     *            the media value for the stylesheet, or null to not specify a specific media type
+     */
+
+    void addStylesheetLink(Asset stylesheet, String media);
 
     /**
      * Adds a script statement to the page's script block (which appears at the end of the page,

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java?rev=586776&r1=586775&r2=586776&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/dom/Element.java Sat Oct 20 12:09:24 2007
@@ -171,14 +171,20 @@
         return child;
     }
 
-    public void comment(String text)
+    /** Adds the comment and returns this element for further construction. */
+    public Element comment(String text)
     {
         newChild(new Comment(this, text));
+
+        return this;
     }
 
-    public void raw(String text)
+    /** Adds the raw text and returns this element for further construction. */
+    public Element raw(String text)
     {
         newChild(new Raw(this, text));
+
+        return this;
     }
 
     /**

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilder.java?rev=586776&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilder.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilder.java Sat Oct 20 12:09:24 2007
@@ -0,0 +1,55 @@
+// Copyright 2007 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.
+// 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.
+
+package org.apache.tapestry.internal.services;
+
+import org.apache.tapestry.dom.Document;
+
+/**
+ * Responsible for injecting script and style links into the <head> element of the rendered
+ * HTML document.
+ */
+public interface DocumentHeadBuilder
+{
+    /** Adds a link to load a script. Scripts will be loaded only once. */
+    void addScriptLink(String scriptURL);
+
+    /**
+     * Adds a link to load a CSS stylesheet. Stylesheets are loaded only once.
+     * 
+     * @param styleURL
+     *            URL of stylesheet to load
+     * @param media
+     *            media value (or null to omit the media attribute)
+     */
+    void addStylesheetLink(String styleURL, String media);
+
+    /**
+     * Adds JavaScript code. The code is collected into a single block that is injected just before
+     * the close body tag of the page.
+     * 
+     * @param script
+     *            statement to add to the block (a newline will be appended as well)
+     */
+    void addScript(String script);
+
+    /**
+     * Updates the supplied Document, locating the html/body element and adding script links (to the
+     * top) and a script block (to the end).
+     * 
+     * @param document
+     *            to be updated
+     */
+    void updateDocument(Document document);
+}

Copied: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImpl.java (from r585511, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImpl.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImpl.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImpl.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImpl.java&r1=585511&r2=586776&rev=586776&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImpl.java Sat Oct 20 12:09:24 2007
@@ -15,19 +15,60 @@
 package org.apache.tapestry.internal.services;
 
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
 
 import java.util.List;
+import java.util.Set;
 
 import org.apache.tapestry.dom.Document;
 import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
 
-public class DocumentScriptBuilderImpl implements DocumentScriptBuilder
+public class DocumentHeadBuilderImpl implements DocumentHeadBuilder
 {
     private final List<String> _scripts = newList();
 
     private final StringBuilder _scriptBlock = new StringBuilder();
 
+    private final Set<String> _stylesheets = newSet();
+
+    private final List<IncludedStylesheet> _includedStylesheets = newList();
+
+    private class IncludedStylesheet
+    {
+        private final String _url;
+
+        private final String _media;
+
+        IncludedStylesheet(String url, String media)
+        {
+            _url = url;
+            _media = media;
+        }
+
+        void add(Element head, int index)
+        {
+            head.elementAt(index, "link",
+
+            "href", _url,
+
+            "rel", "stylesheet",
+
+            "type", "text/css",
+
+            "media", _media);
+        }
+    }
+
+    public void addStylesheetLink(String styleURL, String media)
+    {
+        if (_stylesheets.contains(styleURL)) return;
+
+        _includedStylesheets.add(new IncludedStylesheet(styleURL, media));
+
+        _stylesheets.add(styleURL);
+    }
+
     public void addScriptLink(String scriptURL)
     {
         if (_scripts.contains(scriptURL)) return;
@@ -45,7 +86,30 @@
 
     public void updateDocument(Document document)
     {
-        Element body = document.find("html/body");
+        Element root = document.getRootElement();
+
+        // This can happen due to a catastrophic rendering error, such as a missing page template.
+        if (root == null) return;
+
+        // This only applies when the document is an HTML document. This may need to change in the
+        // future, perhaps configurable, to allow for html and xhtml and perhaps others. Does SVG
+        // use stylesheets?
+
+        if (!root.getName().equals("html")) return;
+
+        int stylesheets = _includedStylesheets.size();
+
+        if (stylesheets > 0)
+        {
+            Element head = root.find("head");
+
+            if (head == null) head = root.elementAt(0, "head");
+
+            for (int i = 0; i < stylesheets; i++)
+                _includedStylesheets.get(i).add(head, i);
+        }
+
+        Element body = root.find("body");
 
         if (body == null) return;
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderSupportImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderSupportImpl.java?rev=586776&r1=586775&r2=586776&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderSupportImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderSupportImpl.java Sat Oct 20 12:09:24 2007
@@ -30,7 +30,7 @@
 {
     private final IdAllocator _idAllocator = new IdAllocator();
 
-    private final DocumentScriptBuilder _builder;
+    private final DocumentHeadBuilder _builder;
 
     private final SymbolSource _symbolSource;
 
@@ -52,7 +52,7 @@
      *            core scripts (evaluated as classpaths scripts) that are added to any page that
      *            includes a script link or script block
      */
-    public PageRenderSupportImpl(DocumentScriptBuilder builder, SymbolSource symbolSource,
+    public PageRenderSupportImpl(DocumentHeadBuilder builder, SymbolSource symbolSource,
             AssetSource assetSource, String... coreScripts)
     {
         _builder = builder;
@@ -98,11 +98,20 @@
 
     public void addScript(String format, Object... arguments)
     {
+        notNull(format, "format");
+
         addCore();
 
         String script = format(format, arguments);
 
         _builder.addScript(script);
+    }
+
+    public void addStylesheetLink(Asset stylesheet, String media)
+    {
+        notNull(stylesheet, "stylesheet");
+
+        _builder.addStylesheetLink(stylesheet.toClientURL(), media);
     }
 
     private void addCore()

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java?rev=586776&r1=586775&r2=586776&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java Sat Oct 20 12:09:24 2007
@@ -42,7 +42,7 @@
 import org.apache.tapestry.internal.services.ComponentInstantiatorSource;
 import org.apache.tapestry.internal.services.ComponentInvocationMap;
 import org.apache.tapestry.internal.services.ComponentTemplateSource;
-import org.apache.tapestry.internal.services.DocumentScriptBuilder;
+import org.apache.tapestry.internal.services.DocumentHeadBuilder;
 import org.apache.tapestry.internal.services.Instantiator;
 import org.apache.tapestry.internal.services.LinkFactory;
 import org.apache.tapestry.internal.services.LinkFactoryListener;
@@ -540,9 +540,9 @@
         return buffer.toString();
     }
 
-    protected final DocumentScriptBuilder mockDocumentScriptBuilder()
+    protected final DocumentHeadBuilder mockDocumentScriptBuilder()
     {
-        return newMock(DocumentScriptBuilder.class);
+        return newMock(DocumentHeadBuilder.class);
     }
 
     protected final void train_canonicalizePageName(ComponentClassResolver resolver,

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java?rev=586776&r1=586775&r2=586776&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java Sat Oct 20 12:09:24 2007
@@ -100,8 +100,8 @@
 import org.apache.tapestry.internal.services.DefaultDataTypeAnalyzer;
 import org.apache.tapestry.internal.services.DefaultInjectionProvider;
 import org.apache.tapestry.internal.services.DefaultValidationDelegateCommand;
-import org.apache.tapestry.internal.services.DocumentScriptBuilder;
-import org.apache.tapestry.internal.services.DocumentScriptBuilderImpl;
+import org.apache.tapestry.internal.services.DocumentHeadBuilder;
+import org.apache.tapestry.internal.services.DocumentHeadBuilderImpl;
 import org.apache.tapestry.internal.services.EnumValueEncoderFactory;
 import org.apache.tapestry.internal.services.EnvironmentImpl;
 import org.apache.tapestry.internal.services.EnvironmentalShadowBuilderImpl;
@@ -113,7 +113,6 @@
 import org.apache.tapestry.internal.services.HeartbeatImpl;
 import org.apache.tapestry.internal.services.InjectContainerWorker;
 import org.apache.tapestry.internal.services.InjectPageWorker;
-import org.apache.tapestry.internal.services.InjectStandardStylesheetCommand;
 import org.apache.tapestry.internal.services.InjectWorker;
 import org.apache.tapestry.internal.services.InternalModule;
 import org.apache.tapestry.internal.services.LinkActionResponseGenerator;
@@ -1432,7 +1431,7 @@
             ThreadLocale threadLocale,
 
             @Path("org/apache/tapestry/default.css")
-            Asset stylesheetAsset,
+            final Asset stylesheetAsset,
 
             @Path("org/apache/tapestry/field-error-marker.png")
             Asset fieldErrorIcon,
@@ -1451,24 +1450,30 @@
 
                 Document document = environment.peek(Document.class);
 
-                DocumentScriptBuilder builder = environment.pop(DocumentScriptBuilder.class);
+                DocumentHeadBuilder builder = environment.pop(DocumentHeadBuilder.class);
 
                 builder.updateDocument(document);
             }
 
             public void setup(Environment environment)
             {
-                DocumentScriptBuilder builder = new DocumentScriptBuilderImpl();
+                DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
 
-                environment.push(DocumentScriptBuilder.class, builder);
-                environment.push(PageRenderSupport.class, new PageRenderSupportImpl(builder,
-                        symbolSource, assetSource,
+                environment.push(DocumentHeadBuilder.class, builder);
+
+                PageRenderSupportImpl support = new PageRenderSupportImpl(builder,
+                        symbolSource,
+                        assetSource,
 
                         // Core scripts added to any page that uses scripting
-                        
+
                         "${tapestry.scriptaculous}/prototype.js",
                         "${tapestry.scriptaculous}/scriptaculous.js",
-                        "org/apache/tapestry/tapestry.js"));
+                        "org/apache/tapestry/tapestry.js");
+
+                support.addStylesheetLink(stylesheetAsset, null);
+
+                environment.push(PageRenderSupport.class, support);
             }
         });
 
@@ -1488,9 +1493,6 @@
                 environment.push(Heartbeat.class, heartbeat);
             }
         });
-
-        configuration.add("InjectStandardStylesheet", new InjectStandardStylesheetCommand(
-                stylesheetAsset));
 
         configuration.add("DefaultValidationDelegate", new DefaultValidationDelegateCommand(
                 threadLocale, validationMessagesSource, fieldErrorIcon));

Copied: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImplTest.java (from r585511, tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImplTest.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImplTest.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImplTest.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImplTest.java&r1=585511&r2=586776&rev=586776&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentScriptBuilderImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/DocumentHeadBuilderImplTest.java Sat Oct 20 12:09:24 2007
@@ -19,8 +19,13 @@
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.testng.annotations.Test;
 
-public class DocumentScriptBuilderImplTest extends InternalBaseTestCase
+public class DocumentHeadBuilderImplTest extends InternalBaseTestCase
 {
+    private void check(Document document, String file) throws Exception
+    {
+        assertEquals(document.toString(), readFile(file, true));
+    }
+
     @Test
     public void do_nothing_if_no_body()
     {
@@ -28,7 +33,7 @@
 
         document.newRootElement("not-html").text("not an HTML document");
 
-        DocumentScriptBuilder builder = new DocumentScriptBuilderImpl();
+        DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
 
         builder.addScript("foo.js");
         builder.addScript("doSomething();");
@@ -46,14 +51,70 @@
         document.newRootElement("html").element("body").element("p").text(
                 "Ready to be updated with scripts.");
 
-        DocumentScriptBuilder builder = new DocumentScriptBuilderImpl();
+        DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
 
         builder.addScriptLink("foo.js");
         builder.addScriptLink("bar/baz.js");
 
         builder.updateDocument(document);
 
-        assertEquals(document.toString(), readFile("add_script_links.txt", true));
+        check(document, "add_script_links.txt");
+    }
+
+    @Test
+    public void add_style_links() throws Exception
+    {
+        Document document = new Document(new XMLMarkupModel());
+
+        document.newRootElement("html").element("body").element("p").text(
+                "Ready to be updated with styles.");
+
+        DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
+
+        builder.addStylesheetLink("foo.css", null);
+        builder.addStylesheetLink("bar/baz.css", "print");
+
+        builder.updateDocument(document);
+
+        check(document, "add_style_links.txt");
+    }
+
+    @Test
+    public void duplicate_scripts_ignored_first_media_wins() throws Exception
+    {
+        Document document = new Document(new XMLMarkupModel());
+
+        document.newRootElement("html").element("body").element("p").text(
+                "Ready to be updated with styles.");
+
+        DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
+
+        builder.addStylesheetLink("foo.css", null);
+        builder.addStylesheetLink("bar/baz.css", "print");
+        builder.addStylesheetLink("foo.css", "implant");
+        builder.addStylesheetLink("bar/baz.css", null);
+        builder.addStylesheetLink("bar/baz.css", "duplicate");
+
+        builder.updateDocument(document);
+
+        check(document, "duplicate_scripts_ignored_first_media_wins.txt");
+    }
+
+    @Test
+    public void existing_head_used_if_present() throws Exception
+    {
+        Document document = new Document(new XMLMarkupModel());
+
+        document.newRootElement("html").element("head").comment("existing head").getParent()
+                .element("body").text("body content");
+
+        DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
+
+        builder.addStylesheetLink("foo.css", null);
+
+        builder.updateDocument(document);
+
+        check(document, "existing_head_used_if_present.txt");
     }
 
     @Test
@@ -64,7 +125,7 @@
         document.newRootElement("html").element("body").element("p").text(
                 "Ready to be updated with scripts.");
 
-        DocumentScriptBuilder builder = new DocumentScriptBuilderImpl();
+        DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
 
         for (int i = 0; i < 3; i++)
         {
@@ -75,7 +136,7 @@
 
         builder.updateDocument(document);
 
-        assertEquals(document.toString(), readFile("duplicate_script_links_ignored.txt", true));
+        check(document, "duplicate_script_links_ignored.txt");
     }
 
     @Test
@@ -86,13 +147,33 @@
         document.newRootElement("html").element("body").element("p").text(
                 "Ready to be updated with scripts.");
 
-        DocumentScriptBuilder builder = new DocumentScriptBuilderImpl();
+        DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
 
         builder.addScript("doSomething();");
         builder.addScript("doSomethingElse();");
 
         builder.updateDocument(document);
 
-        assertEquals(document.toString(), readFile("add_script.txt", false).trim());
+      assertEquals(document.toString(), readFile("add_script.txt", false).trim());
+    }
+
+    /**
+     * Perhaps the builder should create the &lt;body&gt; element in this case? In the meantime,
+     */
+    @Test
+    public void no_body_element() throws Exception
+    {
+        Document document = new Document(new XMLMarkupModel());
+
+        document.newRootElement("html").element("notbody").element("p").text(
+                "Ready to be updated with scripts.");
+
+        DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
+
+        builder.addScriptLink("foo.js");
+
+        builder.updateDocument(document);
+
+        check(document, "no_body_element.txt");
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderSupportImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderSupportImplTest.java?rev=586776&r1=586775&r2=586776&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderSupportImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/PageRenderSupportImplTest.java Sat Oct 20 12:09:24 2007
@@ -34,7 +34,7 @@
     @Test
     public void add_script_link_by_asset()
     {
-        DocumentScriptBuilder builder = mockDocumentScriptBuilder();
+        DocumentHeadBuilder builder = mockDocumentScriptBuilder();
         Asset asset = mockAsset();
 
         train_toClientURL(asset, ASSET_URL);
@@ -55,7 +55,7 @@
         getMocksControl().checkOrder(true);
 
         Asset coreAsset = mockAsset();
-        DocumentScriptBuilder builder = mockDocumentScriptBuilder();
+        DocumentHeadBuilder builder = mockDocumentScriptBuilder();
         Asset asset = mockAsset();
         AssetSource assetSource = mockAssetSource();
         SymbolSource symbolSource = mockSymbolSource();
@@ -82,7 +82,7 @@
     @Test
     public void add_script()
     {
-        DocumentScriptBuilder builder = mockDocumentScriptBuilder();
+        DocumentHeadBuilder builder = mockDocumentScriptBuilder();
 
         builder.addScript("Tapestry.Foo(\"bar\");");
 
@@ -101,7 +101,7 @@
         String path = "${root}/foo/bar.pdf";
         String expanded = "org/apache/tapestry/foo/bar.pdf";
 
-        DocumentScriptBuilder builder = mockDocumentScriptBuilder();
+        DocumentHeadBuilder builder = mockDocumentScriptBuilder();
         Asset asset = mockAsset();
         SymbolSource source = mockSymbolSource();
         AssetSource assetSource = mockAssetSource();
@@ -118,6 +118,25 @@
         PageRenderSupport support = new PageRenderSupportImpl(builder, source, assetSource);
 
         support.addClasspathScriptLink(path);
+
+        verify();
+    }
+
+    @Test
+    public void add_stylesheet_link()
+    {
+        String media = "print";
+        DocumentHeadBuilder builder = mockDocumentScriptBuilder();
+        Asset asset = mockAsset();
+
+        train_toClientURL(asset, ASSET_URL);
+        builder.addStylesheetLink(ASSET_URL, media);
+
+        replay();
+
+        PageRenderSupport support = new PageRenderSupportImpl(builder, null, null);
+
+        support.addStylesheetLink(asset, media);
 
         verify();
     }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/add_style_links.txt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/add_style_links.txt?rev=586776&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/add_style_links.txt (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/add_style_links.txt Sat Oct 20 12:09:24 2007
@@ -0,0 +1 @@
+<html><head><link href="foo.css" rel="stylesheet" type="text/css"/><link href="bar/baz.css" media="print" rel="stylesheet" type="text/css"/></head><body><p>Ready to be updated with styles.</p></body></html>
\ No newline at end of file

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/duplicate_scripts_ignored_first_media_wins.txt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/duplicate_scripts_ignored_first_media_wins.txt?rev=586776&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/duplicate_scripts_ignored_first_media_wins.txt (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/duplicate_scripts_ignored_first_media_wins.txt Sat Oct 20 12:09:24 2007
@@ -0,0 +1 @@
+<html><head><link href="foo.css" rel="stylesheet" type="text/css"/><link href="bar/baz.css" media="print" rel="stylesheet" type="text/css"/></head><body><p>Ready to be updated with styles.</p></body></html>
\ No newline at end of file

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/existing_head_used_if_present.txt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/existing_head_used_if_present.txt?rev=586776&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/existing_head_used_if_present.txt (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/existing_head_used_if_present.txt Sat Oct 20 12:09:24 2007
@@ -0,0 +1 @@
+<html><head><link href="foo.css" rel="stylesheet" type="text/css"/><!-- existing head --></head><body>body content</body></html>
\ No newline at end of file

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/no_body_element.txt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/no_body_element.txt?rev=586776&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/no_body_element.txt (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/internal/services/no_body_element.txt Sat Oct 20 12:09:24 2007
@@ -0,0 +1 @@
+<html><notbody><p>Ready to be updated with scripts.</p></notbody></html>
\ No newline at end of file