Author: hlship
Date: Mon Jun 30 14:08:39 2008
New Revision: 672923
URL: http://svn.apache.org/viewvc?rev=672923&view=rev
Log:
TAPESTRY-2390: Components or mixins requiring external javascript files and
rendered via AJAX do not work
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml
- copied, changed from r669747,
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ZoneDemo.tml
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/ZoneDemo.java
- copied, changed from r669747,
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ZoneDemo.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PartialMarkupRendererFilter.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java?rev=672923&view=auto
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
(added)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java
Mon Jun 30 14:08:39 2008
@@ -0,0 +1,66 @@
+// Copyright 2008 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.tapestry5.internal.services;
+
+import org.apache.tapestry5.json.JSONArray;
+import org.apache.tapestry5.json.JSONObject;
+
+public class PartialMarkupDocumentLinker implements DocumentLinker
+{
+ private final StringBuilder buffer = new StringBuilder(1000);
+
+ private final JSONArray scripts = new JSONArray();
+
+ private final JSONArray stylesheets = new JSONArray();
+
+ public void addScriptLink(String scriptURL)
+ {
+ scripts.put(scriptURL);
+ }
+
+ public void addStylesheetLink(String styleURL, String media)
+ {
+ JSONObject object = new JSONObject();
+ object.put("href", styleURL);
+
+ if (media != null) object.put("media", media);
+
+ stylesheets.put(object);
+ }
+
+ public void addScript(String script)
+ {
+ buffer.append(script);
+ buffer.append("\n");
+ }
+
+ /**
+ * Commits changes, adding one or more keys to the reply.
+ *
+ * @param reply JSON Object to be sent to client
+ */
+ public void commit(JSONObject reply)
+ {
+ if (buffer.length() > 0)
+ reply.put("script", buffer.toString());
+
+ if (scripts.length() > 0)
+ reply.put("scripts", scripts);
+
+ if (stylesheets.length() > 0)
+ reply.put("stylesheets", stylesheets);
+
+ }
+}
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PartialMarkupRendererFilter.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PartialMarkupRendererFilter.java?rev=672923&r1=672922&r2=672923&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PartialMarkupRendererFilter.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PartialMarkupRendererFilter.java
Mon Jun 30 14:08:39 2008
@@ -24,8 +24,8 @@
* pages and components that render.
*
* @see
org.apache.tapestry5.services.TapestryModule#contributePartialMarkupRenderer(org.apache.tapestry5.ioc.OrderedConfiguration,
- * org.apache.tapestry5.Asset, ValidationMessagesSource,
org.apache.tapestry5.ioc.services.SymbolSource,
- * AssetSource)
+ * org.apache.tapestry5.Asset,
org.apache.tapestry5.ioc.services.SymbolSource, AssetSource,
+ * ValidationMessagesSource)
*/
public interface PartialMarkupRendererFilter
{
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=672923&r1=672922&r2=672923&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
Mon Jun 30 14:08:39 2008
@@ -380,7 +380,7 @@
// be converted to clear out at the end of the request.
configuration.add("UnclaimedField", new UnclaimedFieldWorker(),
"after:*");
-
+
configuration.add("PageActivationContext", new
PageActivationContextWorker(), "before:OnEvent");
}
@@ -1515,29 +1515,11 @@
String namespace = ":" + uid;
- final StringBuilder buffer = new StringBuilder(1000);
-
IdAllocator idAllocator = new IdAllocator(namespace);
- DocumentLinker builder = new DocumentLinker()
- {
- public void addScriptLink(String scriptURL)
- {
- }
-
- public void addStylesheetLink(String styleURL, String
media)
- {
- }
-
- public void addScript(String script)
- {
- buffer.append(script);
- buffer.append("\n");
- }
- };
+ PartialMarkupDocumentLinker linker = new
PartialMarkupDocumentLinker();
-
- RenderSupportImpl support = new RenderSupportImpl(builder,
symbolSource, assetSource,
+ RenderSupportImpl support = new RenderSupportImpl(linker,
symbolSource, assetSource,
idAllocator);
environment.push(RenderSupport.class, support);
@@ -1548,8 +1530,7 @@
environment.pop(RenderSupport.class);
- if (buffer.length() > 0)
- reply.put("script", buffer.toString());
+ linker.commit(reply);
}
};
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js?rev=672923&r1=672922&r2=672923&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
Mon Jun 30 14:08:39 2008
@@ -30,11 +30,11 @@
/** Event, triggered on the document object, which identifies the current
focus element. */
FOCUS_CHANGE_EVENT : "tapestry:focuschange",
-
+ /** When false, the default, the Tapestry.debug() function will be a
no-op. */
DEBUG_ENABLED : false,
/** Time, in seconds, that console messages are visible. */
- CONSOLE_DURATION : 10,
+ CONSOLE_DURATION : 60,
FormEvent : Class.create(),
@@ -50,6 +50,8 @@
ErrorPopup : Class.create(),
+ DependentExecutor : Class.create(),
+
// Adds a callback function that will be invoked when the DOM is loaded
(which
// occurs *before* window.onload, which has to wait for images and such to
load
// first. This simply observes the dom:loaded event on the document
object (support for
@@ -66,6 +68,8 @@
*/
onDomLoadedCallback : function()
{
+ Tapestry.ScriptManager.initialize();
+
$$(".t-invisible").each(function(element)
{
element.hide();
@@ -191,13 +195,18 @@
/**
* Passed the JSON content of a Tapestry partial markup response, extracts
- * the script key (if present) and evals it, then uses the DOM loaded
callback
- * to hide invisible fields and add notifications for any form elements.
+ * the script and stylesheet information. JavaScript libraries and
stylesheets are loaded,
+ * then any script code is evaluated. All three keys are optional:
+ * <dl>
+ * <dt>scripts</dt><dd>Array of strings (URIs of scripts)</dd>
+ * <dt>stylesheets</dt><dd>Array of hashes, each hash has key href and
optional key media</dd>
+ * <dt>script</dt> <dd>JavaScript to be executed once all scripts are
loaded</dd></dl>
*/
processScriptInReply : function(reply)
{
- if (reply.script != undefined)
- eval(reply.script);
+ Tapestry.ScriptManager.addScripts(reply.scripts, reply.script);
+
+ Tapestry.ScriptManager.addStylesheets(reply.stylesheets);
Tapestry.onDomLoadedCallback();
},
@@ -267,7 +276,60 @@
ajaxRequest : function(url, successHandler)
{
return new Ajax.Request(url, { onSuccess: successHandler, onFailure:
Tapestry.ajaxFailureHandler })
+ },
+
+
+ /**
+ * Used to reconstruct a complete URL from a path that is (or may be)
relative to window.location.
+ * This is used when determining if a JavaScript library or CSS stylesheet
has already been loaded.
+ * Recognizes complete URLs (which are returned unchanged) and absolute
paths (which are prefixed
+ * with the window.location protocol and host). Otherwise the correct
path is built. The
+ * path may be prefixed with "./" and "../", which will be resolved
correctly.
+ *
+ * @param path
+ * @return complete URL as string
+ */
+ rebuildURL : function(path)
+ {
+ if (path.match(/^https?:/))
+ {
+ return path;
+ }
+
+ if (path.startsWith("/"))
+ {
+ var l = window.location;
+ return l.protocol + "//" + l.host + path;
+ }
+
+ var rootPath = this.stripToLastSlash(window.location.href);
+
+ while (true)
+ {
+ if (path.startsWith("../"))
+ {
+ rootPath = this.stripToLastSlash(rootPath.substr(0,
rootPath.length - 1));
+ path = path.substring(3);
+ continue;
+ }
+
+ if (path.startsWith("./"))
+ {
+ path = path.substr(2);
+ continue;
+ }
+
+ return rootPath + path;
+ }
+ },
+
+ stripToLastSlash : function(URL)
+ {
+ var slashx = URL.lastIndexOf("/");
+
+ return URL.substring(0, slashx + 1);
}
+
};
/** Container of functions that may be invoked by the Tapestry.init()
function. */
@@ -460,8 +522,9 @@
Element.addMethods(Tapestry.ElementAdditions);
// Look for the Firebug console API and rewrite the Tapestry.error|warn|debug
methods around it.
+// This seems to be broken under FireFox 3. It has been disabled until we
deterimine what is broken.
-if (window.console)
+if (false && window.console)
{
var createlog = function (log)
{
@@ -1079,4 +1142,174 @@
}
};
+/**
+ * Coordinates the execution of JavaScript code blocks (via eval) with the
loading
+ * of an array of <script> elements.
+ */
+Tapestry.DependentExecutor.prototype = {
+
+ initialize : function(prereqs, dependent)
+ {
+ this.dependent = dependent;
+ this.loaded = 0;
+ this.toload = prereqs.length;
+
+ var executor = this;
+
+ prereqs.each(function (scriptElement)
+ {
+ if (Prototype.Browser.IE)
+ {
+ var loaded = false;
+
+ scriptElement.onreadystatechange = function ()
+ {
+ Tapestry.debug("State #{state} for #{script} (loaded is
#{loaded})", { state:this.readyState, script:scriptElement.src, loaded:loaded
});
+
+ // IE may fire either loaded or complete, or perhaps even
both.
+ if (! loaded && (this.readyState == 'loaded' ||
this.readyState == 'complete'))
+ {
+ loaded = true;
+ executor.loadComplete(scriptElement);
+ }
+ };
+ }
+ else
+ {
+ // Much simpler in FF, Safari, etc.
+ scriptElement.onload =
executor.loadComplete.bindAsEventListener(executor, scriptElement);
+ }
+ });
+ },
+
+ loadComplete : function(element)
+ {
+ this.loaded++;
+
+ Tapestry.debug("Script #{loaded} of #{toload} loaded", this);
+
+ // Evaluated the dependent script only once all the elements have
loaded.
+
+ if (this.loaded == this.toload)
+ eval(this.dependent);
+ }
+};
+
+Tapestry.ScriptManager = {
+
+ initialize : function()
+ {
+
+ // Check to see if document.script is supported; if not (for example,
FireFox),
+ // we can fake it.
+
+ this.emulated = false;
+
+ if (! document.scripts)
+ {
+ this.emulated = true;
+
+ document.scripts = new Array();
+
+ $$('script').each(function (s)
+ {
+ document.scripts.push(s);
+ });
+ }
+ },
+
+ /**
+ * Checks to see if the given collection (of <script> or <style> elements)
contains the given asset URL.
+ * @param collection
+ * @param prop property to check ('src' for script, 'href' to style).
+ * @param assetURL complete URL (i.e., with protocol, host and
port) to the asset
+ */
+ contains : function (collection, prop, assetURL)
+ {
+ Tapestry.debug("Checking previously loaded for: " + assetURL);
+
+ return $A(collection).any(function (element)
+ {
+ var existing = element[prop];
+
+ if (existing.blank()) return false;
+
+ var complete =
+ Prototype.Browser.IE ? Tapestry.rebuildURL(existing) :
existing;
+
+ Tapestry.debug("Previously loaded: " + complete);
+
+ return complete == assetURL;
+ });
+
+ return false;
+ },
+
+ addScripts: function(scripts, dependent)
+ {
+ var added = new Array();
+
+ if (scripts)
+ {
+ var emulated = this.emulated;
+ // Looks like IE really needs the new <script> tag to be
+ // in the <head>. FF doesn't seem to care.
+ // See http://unixpapa.com/js/dyna.html
+ var head = $$("head").first();
+
+ scripts.each(function(s)
+ {
+ var assetURL = Tapestry.rebuildURL(s);
+
+ if (Tapestry.ScriptManager.contains(document.scripts, "src",
assetURL)) return; // continue to next script
+
+ Tapestry.debug("Loading script: " + assetURL);
+
+ var element = new Element('script', { src: assetURL, type:
'text/javascript' });
+
+ head.insert({bottom:element});
+
+ added.push(element);
+
+ if (emulated) document.scripts.push(element);
+ });
+
+ }
+
+ if (!dependent) return;
+
+ if (added.length)
+ {
+ new Tapestry.DependentExecutor(added, dependent);
+ return;
+ }
+
+ eval(dependent);
+ },
+
+ addStylesheets : function(stylesheets)
+ {
+ if (!stylesheets) return;
+
+ var head = $$('head').first();
+
+ $(stylesheets).each(function(s)
+ {
+ var assetURL = Tapestry.rebuildURL(s);
+
+ if (Tapestry.ScriptManager.contains(document.styleSheets, 'href',
assetURL)) return; // continue
+
+ var element = new Element('link', { type: 'text/css', rel:
'stylesheet', href: assetURL });
+
+ // Careful about media types, some browser will break if it ends
up as 'null'.
+
+ if (s.media != undefined)
+ element.writeAttribute('media', s.media);
+
+ head.insert({bottom: element});
+
+ });
+ }
+};
+
Tapestry.onDOMLoaded(Tapestry.onDomLoadedCallback);
Copied:
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml (from
r669747, tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ZoneDemo.tml)
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml?p2=tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml&p1=tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ZoneDemo.tml&r1=669747&r2=672923&rev=672923&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ZoneDemo.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml
Mon Jun 30 14:08:39 2008
@@ -17,14 +17,24 @@
<t:block id="registrationForm">
- <t:beaneditform t:id="form" object="registration" zone="output"/>
+ <t:beaneditform t:id="form" object="registration" zone="output"
add="roles">
+
+ <t:parameter name="roles">
+ <t:palette selected="registration.roles" encoder="encoder"
model="literal:guest,user,admin"/>
+ </t:parameter>
+
+ </t:beaneditform>
<t:actionlink t:id="clear" zone="output">clear</t:actionlink>
</t:block>
<t:block id="registrationOutput">
- <t:beandisplay object="registration"/>
+ <t:beandisplay object="registration" add="roles">
+ <t:parameter name="roles">
+ ${registration.roles}
+ </t:parameter>
+ </t:beandisplay>
</t:block>
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java?rev=672923&r1=672922&r2=672923&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java
Mon Jun 30 14:08:39 2008
@@ -18,6 +18,9 @@
import org.apache.tapestry5.beaneditor.ReorderProperties;
import org.apache.tapestry5.beaneditor.Validate;
import org.apache.tapestry5.beaneditor.Width;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+
+import java.util.List;
@ReorderProperties("firstname,lastname,birthyear,sex")
public class RegistrationData
@@ -36,6 +39,8 @@
private String notes;
+ private List<String> roles = CollectionFactory.newList();
+
@Validate("min=1900,max=2007")
@Width(4)
public int getBirthYear()
@@ -113,4 +118,14 @@
{
this.notes = notes;
}
+
+ public List<String> getRoles()
+ {
+ return roles;
+ }
+
+ public void setRoles(List<String> roles)
+ {
+ this.roles = roles;
+ }
}
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java?rev=672923&r1=672922&r2=672923&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java
Mon Jun 30 14:08:39 2008
@@ -138,7 +138,7 @@
new Item("MissingTemplate", "Missing Template Demo",
"Demo for what happens when a template is not found for a
page"),
- new Item("zonedemo", "Zone Demo", "dynamic updates within a page"),
+ new Item("nested/zonedemo", "Zone Demo", "dynamic updates within a
page"),
new Item("todolist", "ToDo List", "Loops and Submit inside Form
using primary key encoder"),
Copied:
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/ZoneDemo.java
(from r669747,
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ZoneDemo.java)
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/ZoneDemo.java?p2=tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/ZoneDemo.java&p1=tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ZoneDemo.java&r1=669747&r2=672923&rev=672923&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ZoneDemo.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/ZoneDemo.java
Mon Jun 30 14:08:39 2008
@@ -12,14 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry5.integration.app1.pages;
+package org.apache.tapestry5.integration.app1.pages.nested;
import org.apache.tapestry5.Block;
+import org.apache.tapestry5.ValueEncoder;
import org.apache.tapestry5.annotations.ApplicationState;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.Log;
import org.apache.tapestry5.corelib.components.BeanEditForm;
import org.apache.tapestry5.integration.app1.data.RegistrationData;
+import org.apache.tapestry5.internal.services.StringValueEncoder;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.json.JSONObject;
@@ -103,4 +105,9 @@
{
return new Date();
}
+
+ public ValueEncoder<String> getEncoder()
+ {
+ return new StringValueEncoder();
+ }
}
Added:
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java?rev=672923&view=auto
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java
(added)
+++
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinkerTest.java
Mon Jun 30 14:08:39 2008
@@ -0,0 +1,70 @@
+// Copyright 2008 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.tapestry5.internal.services;
+
+import org.apache.tapestry5.json.JSONObject;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class PartialMarkupDocumentLinkerTest extends Assert
+{
+ @Test
+ public void script()
+ {
+ PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker();
+
+ linker.addScript("foo();");
+ linker.addScript("bar();");
+
+ JSONObject reply = new JSONObject();
+
+ linker.commit(reply);
+
+ assertEquals(reply.get("script"), "foo();\nbar();\n");
+ }
+
+ @Test
+ public void script_link()
+ {
+ PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker();
+
+ linker.addScriptLink("foo.js");
+ linker.addScriptLink("bar.js");
+
+ JSONObject reply = new JSONObject();
+
+ linker.commit(reply);
+
+ assertEquals(reply.toString(),
"{\"scripts\":[\"foo.js\",\"bar.js\"]}");
+
+ }
+
+ @Test
+ public void stylesheet_link()
+ {
+ PartialMarkupDocumentLinker linker = new PartialMarkupDocumentLinker();
+
+ linker.addStylesheetLink("foo.css", "print");
+ linker.addStylesheetLink("bar.css", null);
+
+ JSONObject reply = new JSONObject();
+
+ linker.commit(reply);
+
+ assertEquals(reply.toString(),
+
"{\"stylesheets\":[{\"href\":\"foo.css\",\"media\":\"print\"},{\"href\":\"bar.css\"}]}");
+
+ }
+}