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 2011/10/20 01:23:32 UTC
svn commit: r1186564 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/resources/org/apache/tapestry5/ test/app1/nested/
test/java/org/apache/tapestry5/integration/app1/
test/java/org/apache/tapestry5/integration/app1/pages/nested/
test/resources/...
Author: hlship
Date: Wed Oct 19 23:23:31 2011
New Revision: 1186564
URL: http://svn.apache.org/viewvc?rev=1186564&view=rev
Log:
TAP5-1708: Add ability to control where Ajax-injected CSS links are placed
Added:
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-overrides.css
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-viaajax.css
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/ZoneDemo.java
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=1186564&r1=1186563&r2=1186564&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 Wed Oct 19 23:23:31 2011
@@ -2042,32 +2042,8 @@ Tapestry.ScriptManager = {
element.onload = callback.bindAsEventListener(this);
},
- /**
- * 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) {
- return $A(collection).any(
- function(element) {
- var existing = element[prop];
-
- if (!existing || existing.blank())
- return false;
-
- var complete = Prototype.Browser.IE ? Tapestry
- .rebuildURL(existing) : existing;
-
- return complete == assetURL;
- });
-
- return false;
- },
+ rebuildURLIfIE :
+ Prototype.Browser.IE ? Tapestry.rebuildURL : T5._.identity,
/**
* Add scripts, as needed, to the document, then waits for them all to load,
@@ -2080,68 +2056,64 @@ Tapestry.ScriptManager = {
*/
addScripts : function(scripts, callback) {
- var scriptsToLoad = [];
+ var _ = T5._;
- /* scripts may be null or undefined */
- (scripts || []).each(function(s) {
- var assetURL = Tapestry.rebuildURL(s);
+ var loaded = _(document.scripts).chain().pluck("src").without("").map(this.rebuildURLIfIE).value();
- if (Tapestry.ScriptManager.contains(document.scripts, "src",
- assetURL))
- return;
+ var topCallback = _(scripts).chain().map(Tapestry.rebuildURL).difference(loaded).reverse().reduce(
+ function (nextCallback, scriptURL) {
+ return function() {
+ this.loadScript(scriptURL, nextCallback);
+ }
+ }, callback).value();
- scriptsToLoad.push(assetURL);
- });
+ // Kick if off with the callback that loads the first script:
- /*
- * Set it up last script to first script. The last script's callback is
- * the main callback (the code to execute after all scripts are loaded).
- * The 2nd to last script's callback loads the last script. Prototype's
- * Array.inject() is effectively the same as Clojure's reduce().
- */
- scriptsToLoad.reverse();
-
- var topCallback = scriptsToLoad.inject(callback, function(nextCallback, scriptURL) {
- return function() {
- Tapestry.ScriptManager.loadScript(scriptURL, nextCallback);
- };
- });
-
- /* Kick it off with the callback that loads the first script. */
- topCallback.call();
+ topCallback.call(this);
},
+ /**
+ * Adds stylesheets to the document. Each element in stylesheets is an object with two keys: href (the URL to the CSS file) and
+ * (optionally) media.
+ * @param stylesheets
+ */
addStylesheets : function(stylesheets) {
if (!stylesheets)
return;
+ var _ = T5._;
+
+ var loaded = _(document.styleSheets).chain().pluck("href").without("").map(this.rebuildURLIfIE).value();
+
+ var toLoad = _(stylesheets).chain().map(
+ function(ss) {
+ ss.href = Tapestry.rebuildURL(ss.href);
+
+ return ss;
+ }).reject(
+ function (ss) {
+ return _(loaded).contains(ss.href);
+ }).value();
+
+
var head = $$('head').first();
- $(stylesheets).each(
- function(s) {
- var assetURL = Tapestry.rebuildURL(s.href);
-
- if (Tapestry.ScriptManager.contains(document.styleSheets,
- 'href', assetURL))
- return;
- 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
- });
+ var insertionPoint = head.down("link[rel='stylesheet t-ajax-insertion-point']");
- });
+ _(toLoad).each(function(ss) {
+
+ var element = new Element('link', { type: 'text/css', rel: 'stylesheet', href: ss.href });
+ if (ss.media) {
+ element.writeAttribute('media', ss.media);
+ }
+
+ if (insertionPoint) {
+ insertionPoint.insert({ before: element });
+ }
+ else {
+ head:insert({bottom: element});
+ }
+ });
}
};
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml?rev=1186564&r1=1186563&r2=1186564&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/nested/ZoneDemo.tml Wed Oct 19 23:23:31 2011
@@ -1,106 +1,117 @@
<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd" xml:space="default">
- <h1>Zone/Ajax Demo</h1>
+ <h1>Zone/Ajax Demo</h1>
- <h2>Last update: ${currentTime}</h2>
+ <h2>Last update: ${currentTime}</h2>
- <t:zone t:id="output" style="float:right; width: 800px;" update="slidedown">
+ <t:zone t:id="output" style="float:right; width: 800px;" update="slidedown">
<span class="t-zone-update">
<t:if test="name" else="No name has been selected.">
- Selected: ${name}
- </t:if>
+ Selected: ${name}
+ </t:if>
</span>
- </t:zone>
+ </t:zone>
- <t:block id="registrationForm">
+ <t:block id="ajaxCSS">
+ <div id="demo-aip">
+ <p>
+ This should be styled GREEN.
+ </p>
+ </div>
- <t:beaneditform t:id="registrationForm" object="registration" zone="^" add="roles">
+ </t:block>
+
+ <t:block id="registrationForm">
- <t:parameter name="roles">
- <t:palette selected="registration.roles" encoder="encoder" model="literal:guest,user,admin"/>
- </t:parameter>
- </t:beaneditform>
+ <t:beaneditform t:id="registrationForm" object="registration" zone="^" add="roles">
- <t:actionlink t:id="clear" zone="output">clear</t:actionlink>
+ <t:parameter name="roles">
+ <t:palette selected="registration.roles" encoder="encoder" model="literal:guest,user,admin"/>
+ </t:parameter>
- </t:block>
+ </t:beaneditform>
- <t:block id="registrationOutput">
- <t:beandisplay object="registration" add="roles">
- <t:parameter name="roles">
- ${registration.roles}
+ <t:actionlink t:id="clear" zone="output">clear</t:actionlink>
+
+ </t:block>
+
+ <t:block id="registrationOutput">
+ <t:beandisplay object="registration" add="roles">
+ <t:parameter name="roles">
+ ${registration.roles}
</t:parameter>
- </t:beandisplay>
- </t:block>
+ </t:beandisplay>
+ </t:block>
+
+ <t:block id="voteForm">
+ <t:form t:id="vote" zone="^">
+ Vote:
+ <input type="submit" name="abstain" value="Abstain"/>
+ <t:submit t:id="voteYes" value="Yes"/>
+ <t:submit t:id="voteNo" value="No"/>
+ </t:form>
+ </t:block>
- <t:block id="voteForm">
- <t:form t:id="vote" zone="^">
- Vote:
- <input type="submit" name="abstain" value="Abstain"/>
- <t:submit t:id="voteYes" value="Yes"/>
- <t:submit t:id="voteNo" value="No"/>
- </t:form>
- </t:block>
-
- <t:block id="voteOutput">
- You voted: ${vote}
- </t:block>
-
-
- <ul>
- <li t:type="loop" source="names" value="name">
- <t:actionlink t:id="select" context="name" zone="output">Select "${name}"</t:actionlink>
- </li>
- <li>
- <t:actionlink t:id="JSON" zone="output">Direct JSON response</t:actionlink>
- </li>
- <li>
- <t:actionlink t:id="fail" zone="output">Failure on the server side</t:actionlink>
- </li>
- <li>
- <t:actionlink t:id="redirect" zone="output">Perform a redirect to another page
- </t:actionlink>
- </li>
- <li>
- <t:actionlink t:id="secureRedirect" zone="output">Perform secure redirect to another page
- </t:actionlink>
- </li>
- <li>
- <t:actionlink t:id="blankUpdate" zone="output">Blank the zone</t:actionlink>
- </li>
- <li>
- <t:actionlink t:id="poorlyFormattedFail" zone="output">Poorly formatted server-side
- failure</t:actionlink>
- </li>
- <li>
- <t:actionlink t:id="badZone" zone="output">
- MultiZone update with unknown id
- </t:actionlink>
- </li>
- <li>
- <t:actionlink t:id="nonZoneUpdate" zone="output">
- MultiZone update with id of non-Zone
- element
- </t:actionlink>
- </li>
- </ul>
-
- <div id="notAZone"/>
-
- <t:block id="empty"/>
-
- <t:block id="forUnknownZone">
- <p>Content for the unknown zone.</p>
- </t:block>
-
- <t:block id="forNotAZone">
- <p>Content for zone update for a non-Zone element.</p>
- </t:block>
+ <t:block id="voteOutput">
+ You voted: ${vote}
+ </t:block>
+
+
+ <ul>
+ <li t:type="loop" source="names" value="name">
+ <t:actionlink t:id="select" context="name" zone="output">Select "${name}"</t:actionlink>
+ </li>
+ <li>
+ <t:actionlink t:id="JSON" zone="output">Direct JSON response</t:actionlink>
+ </li>
+ <li>
+ <t:actionlink t:id="fail" zone="output">Failure on the server side</t:actionlink>
+ </li>
+ <li>
+ <t:actionlink t:id="redirect" zone="output">Perform a redirect to another page
+ </t:actionlink>
+ </li>
+ <li>
+ <t:actionlink t:id="secureRedirect" zone="output">Perform secure redirect to another page
+ </t:actionlink>
+ </li>
+ <li>
+ <t:actionlink t:id="blankUpdate" zone="output">Blank the zone</t:actionlink>
+ </li>
+ <li>
+ <t:actionlink t:id="poorlyFormattedFail" zone="output">Poorly formatted server-side
+ failure
+ </t:actionlink>
+ </li>
+ <li>
+ <t:actionlink t:id="badZone" zone="output">
+ MultiZone update with unknown id
+ </t:actionlink>
+ </li>
+ <li>
+ <t:actionlink t:id="nonZoneUpdate" zone="output">
+ MultiZone update with id of non-Zone
+ element
+ </t:actionlink>
+ </li>
+ </ul>
+
+ <div id="notAZone"/>
+
+ <t:block id="empty"/>
+
+ <t:block id="forUnknownZone">
+ <p>Content for the unknown zone.</p>
+ </t:block>
+
+ <t:block id="forNotAZone">
+ <p>Content for zone update for a non-Zone element.</p>
+ </t:block>
- <div id="zone-update-message"/>
+ <div id="zone-update-message"/>
</html>
\ No newline at end of file
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java?rev=1186564&r1=1186563&r2=1186564&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java Wed Oct 19 23:23:31 2011
@@ -235,7 +235,9 @@ public class ZoneTests extends TapestryC
assertEquals(color, "rgb(255, 255, 255)");
}
- /** TAP5-1084 */
+ /**
+ * TAP5-1084
+ */
@Test
public void update_zone_inside_form()
{
@@ -252,7 +254,9 @@ public class ZoneTests extends TapestryC
assertText("output", "Tapestry 5.2");
}
- /** TAP5-1109 */
+ /**
+ * TAP5-1109
+ */
@Test
public void update_to_zone_inside_form()
{
@@ -266,13 +270,15 @@ public class ZoneTests extends TapestryC
}
@Test
- public void multi_zone_update_using_string_in_loop() {
+ public void multi_zone_update_using_string_in_loop()
+ {
openLinks("MultiZone String Body Demo");
String[] numbers = new String[]{
"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"
};
- for (int i = 0; i <= 10; i++) {
+ for (int i = 0; i <= 10; i++)
+ {
assertText("row-" + i, numbers[i]);
}
@@ -280,11 +286,13 @@ public class ZoneTests extends TapestryC
waitForElementToAppear("row-7");
// 7- are unchanged
- for (int i = 0; i <= 7; i++) {
+ for (int i = 0; i <= 7; i++)
+ {
assertText("row-" + i, numbers[i]);
}
// 8+ are modified
- for (int i = 8; i <= 10; i++) {
+ for (int i = 8; i <= 10; i++)
+ {
assertText("row-" + i, i + " is the integer value");
}
@@ -292,11 +300,42 @@ public class ZoneTests extends TapestryC
waitForElementToAppear("wholeLoopZone");
// all elements reset via AJAX
- for (int i = 0, numbersLength = numbers.length; i < numbersLength; i++) {
+ for (int i = 0, numbersLength = numbers.length; i < numbersLength; i++)
+ {
assertText("row-" + i, numbers[i]);
}
}
-
+
+ private void assertCSS(String elementId, String cssProperty, String expected)
+ {
+ // See http://groups.google.com/group/selenium-users/browse_thread/thread/f21e0a43c9913d42
+
+ String actual = selenium.getEval(String.format("window.document.defaultView.getComputedStyle(window.document.getElementById('%s'), null).getPropertyValue('%s')",
+ elementId, cssProperty));
+
+ assertEquals(actual, expected, String.format("CSS property '%s' of '%s' should be '%s'.", cssProperty, elementId, expected));
+ }
+
+ @Test
+ public void css_insertion_point()
+ {
+ openLinks("Zone Demo");
+
+ click("link=Select \"CSS Injection\"");
+
+ sleep(100);
+
+ // First check that the update arrived
+
+ assertText("demo-aip", "This should be styled GREEN.");
+
+ // Next see if we can verify that the presentation matches the exceptations; greend and underlined. Underlined from
+ // zonedemo-viaajax.css; green from zonedmeo-overrides.css (not blue as defined in zonedemo-viaajax.css).
+
+
+ assertCSS("demo-aip", "color", "rgb(0, 128, 0)");
+ assertCSS("demo-aip", "text-decoration", "underline");
+ }
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/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?rev=1186564&r1=1186563&r2=1186564&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/ZoneDemo.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/ZoneDemo.java Wed Oct 19 23:23:31 2011
@@ -14,21 +14,12 @@
package org.apache.tapestry5.integration.app1.pages.nested;
-import java.util.Date;
-
+import org.apache.tapestry5.Asset;
import org.apache.tapestry5.Block;
import org.apache.tapestry5.QueryParameterConstants;
-import org.apache.tapestry5.RenderSupport;
import org.apache.tapestry5.ValueEncoder;
import org.apache.tapestry5.ajax.MultiZoneUpdate;
-import org.apache.tapestry5.annotations.Component;
-import org.apache.tapestry5.annotations.Environmental;
-import org.apache.tapestry5.annotations.InjectComponent;
-import org.apache.tapestry5.annotations.InjectPage;
-import org.apache.tapestry5.annotations.Log;
-import org.apache.tapestry5.annotations.Property;
-import org.apache.tapestry5.annotations.RequestParameter;
-import org.apache.tapestry5.annotations.SessionState;
+import org.apache.tapestry5.annotations.*;
import org.apache.tapestry5.corelib.components.BeanEditForm;
import org.apache.tapestry5.corelib.components.Zone;
import org.apache.tapestry5.integration.app1.data.RegistrationData;
@@ -36,6 +27,13 @@ import org.apache.tapestry5.integration.
import org.apache.tapestry5.internal.services.StringValueEncoder;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
+import org.apache.tapestry5.services.ajax.JavaScriptCallback;
+import org.apache.tapestry5.services.javascript.JavaScriptSupport;
+import org.apache.tapestry5.services.javascript.StylesheetLink;
+import org.apache.tapestry5.services.javascript.StylesheetOptions;
+
+import java.util.Date;
public class ZoneDemo
{
@@ -48,10 +46,10 @@ public class ZoneDemo
private RegistrationData registration;
private static final String[] NAMES =
- { "Fred & Wilma", "Mr. <Roboto>", "Grim Fandango", "Registration", "Vote" };
+ {"Fred & Wilma", "Mr. <Roboto>", "Grim Fandango", "Registration", "Vote", "CSS Injection"};
@Inject
- private Block registrationForm, registrationOutput, voteForm, voteOutput, empty, forUnknownZone, forNotAZone;
+ private Block registrationForm, registrationOutput, voteForm, voteOutput, empty, forUnknownZone, forNotAZone, ajaxCSS;
@Property
private String vote;
@@ -63,7 +61,18 @@ public class ZoneDemo
private SecurePage securePage;
@Environmental
- private RenderSupport renderSupport;
+ private JavaScriptSupport jss;
+
+ @Inject
+ private AjaxResponseRenderer ajaxResponseRenderer;
+
+ @Inject
+ @Path("zonedemo-overrides.css")
+ private Asset overridesCSS;
+
+ @Inject
+ @Path("zonedemo-viaajax.css")
+ private Asset viaAjaxCSS;
public String[] getNames()
{
@@ -90,10 +99,27 @@ public class ZoneDemo
this.name = name;
if (name.equals("Registration"))
+ {
return registrationForm;
+ }
if (name.equals("Vote"))
+ {
return voteForm;
+ }
+
+ if (name.equals("CSS Injection"))
+ {
+ ajaxResponseRenderer.addCallback(new JavaScriptCallback()
+ {
+ public void run(JavaScriptSupport javascriptSupport)
+ {
+ javascriptSupport.importStylesheet(viaAjaxCSS);
+ }
+ });
+
+ return ajaxCSS;
+ }
return output.getBody();
}
@@ -177,10 +203,11 @@ public class ZoneDemo
void afterRender()
{
- renderSupport
- .addScript(
- "$('%s').observe(Tapestry.ZONE_UPDATED_EVENT, function() { $('zone-update-message').update('Zone updated.'); });",
- output.getClientId());
+ jss.importStylesheet(new StylesheetLink(overridesCSS, new StylesheetOptions().asAjaxInsertionPoint()));
+
+ jss.addScript(
+ "$('%s').observe(Tapestry.ZONE_UPDATED_EVENT, function() { $('zone-update-message').update('Zone updated.'); });",
+ output.getClientId());
}
Object onActionFromBadZone()
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-overrides.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-overrides.css?rev=1186564&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-overrides.css (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-overrides.css Wed Oct 19 23:23:31 2011
@@ -0,0 +1,7 @@
+/* Used by ZoneDemo page
+
+ Contains overrides of CSS from other CSS files, so it is ordered last AND is the Ajax insertion point. */
+
+#demo-aip {
+ color: green;
+}
\ No newline at end of file
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-viaajax.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-viaajax.css?rev=1186564&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-viaajax.css (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/zonedemo-viaajax.css Wed Oct 19 23:23:31 2011
@@ -0,0 +1,9 @@
+/* Used by ZoneDemo page
+
+ This is injected via Ajax. */
+
+#demo-aip {
+ color: blue;
+ font-size: large;
+ text-decoration: underline;
+}
\ No newline at end of file