SWF-785 - Spring Faces creates XHTML-incompatible JavaScript scripts

This commit is contained in:
Jeremy Grelle
2008-07-28 18:23:25 +00:00
parent 6ce86e2712
commit ab5bfb55f7
15 changed files with 83 additions and 71 deletions

View File

@@ -23,6 +23,7 @@ import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.ActionEvent;
import org.springframework.faces.ui.resource.ResourceHelper;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -39,9 +40,9 @@ public class AjaxEventInterceptorRenderer extends DojoDecorationRenderer {
Assert.hasText(event, "The event attribute is required on " + component);
Assert.isTrue(component.getChildCount() == 1, "Exactly one child component is required for " + component);
ResourceHelper.beginScriptBlock(context);
ResponseWriter writer = context.getResponseWriter();
writer.startElement("script", component);
writer.writeAttribute("type", "text/javascript", null);
String processIds = (String) component.getAttributes().get("processIds");
if (StringUtils.hasText(processIds) && !processIds.contains(component.getClientId(context))) {
@@ -60,7 +61,8 @@ public class AjaxEventInterceptorRenderer extends DojoDecorationRenderer {
script.append(", ajaxSource : '" + component.getClientId(context) + "'} }));");
writer.writeText(script.toString(), null);
writer.endElement("script");
ResourceHelper.endScriptBlock(context);
}
private String getElementId(FacesContext context, UIComponent component) {

View File

@@ -34,6 +34,7 @@ import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import javax.faces.lifecycle.Lifecycle;
import org.springframework.faces.ui.resource.ResourceHelper;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.webflow.execution.View;
@@ -201,10 +202,9 @@ public class AjaxViewRoot extends DelegatingViewRoot {
if (StringUtils.hasLength(formId)) {
String script = "dojo.byId('" + formId + "').action = '"
+ context.getApplication().getViewHandler().getActionURL(context, getViewId()) + "'";
writer.startElement("script", null);
writer.writeAttribute("type", "text/javascript", null);
ResourceHelper.beginScriptBlock(context);
writer.writeText(script, null);
writer.endElement("script");
ResourceHelper.endScriptBlock(context);
}
} catch (IOException e) {
e.printStackTrace();

View File

@@ -41,17 +41,15 @@ public abstract class BaseDojoComponentRenderer extends BaseSpringJavascriptComp
private String springDojoJsResourceUri = "/spring/Spring-Dojo.js";
private ResourceHelper resourceHelper = new ResourceHelper();
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
super.encodeBegin(context, component);
if (!JsfUtils.isAsynchronousFlowRequest()) {
resourceHelper.renderStyleLink(context, dijitThemePath + dijitTheme + "/" + dijitTheme + ".css");
ResourceHelper.renderStyleLink(context, dijitThemePath + dijitTheme + "/" + dijitTheme + ".css");
resourceHelper.renderScriptLink(context, dojoJsResourceUri);
ResourceHelper.renderScriptLink(context, dojoJsResourceUri);
resourceHelper.renderScriptLink(context, springDojoJsResourceUri);
ResourceHelper.renderScriptLink(context, springDojoJsResourceUri);
}
}

View File

@@ -34,14 +34,12 @@ public abstract class BaseSpringJavascriptComponentRenderer extends BaseComponen
private String springJsResourceUri = "/spring/Spring.js";
private ResourceHelper resourceHelper = new ResourceHelper();
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
super.encodeBegin(context, component);
if (!JsfUtils.isAsynchronousFlowRequest()) {
resourceHelper.renderScriptLink(context, springJsResourceUri);
ResourceHelper.renderScriptLink(context, springJsResourceUri);
}
}
}

View File

@@ -28,12 +28,10 @@ public abstract class BaseSpringJavascriptDecorationRenderer extends Renderer {
private String springJsResourceUri = "/spring/Spring.js";
private ResourceHelper resourceHelper = new ResourceHelper();
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
if (!JsfUtils.isAsynchronousFlowRequest()) {
resourceHelper.renderScriptLink(context, springJsResourceUri);
ResourceHelper.renderScriptLink(context, springJsResourceUri);
}
}

View File

@@ -38,8 +38,6 @@ import org.springframework.util.StringUtils;
*/
public class DojoDecorationRenderer extends BaseSpringJavascriptDecorationRenderer {
private static final String SCRIPT_ELEMENT = "script";
private String dojoJsResourceUri = "/dojo/dojo.js";
private String dijitThemePath = "/dijit/themes/";
@@ -48,18 +46,16 @@ public class DojoDecorationRenderer extends BaseSpringJavascriptDecorationRender
private String springDojoJsResourceUri = "/spring/Spring-Dojo.js";
private ResourceHelper resourceHelper = new ResourceHelper();
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
super.encodeBegin(context, component);
if (!JsfUtils.isAsynchronousFlowRequest()) {
resourceHelper.renderStyleLink(context, dijitThemePath + dijitTheme + "/" + dijitTheme + ".css");
ResourceHelper.renderStyleLink(context, dijitThemePath + dijitTheme + "/" + dijitTheme + ".css");
resourceHelper.renderScriptLink(context, dojoJsResourceUri);
ResourceHelper.renderScriptLink(context, dojoJsResourceUri);
resourceHelper.renderScriptLink(context, springDojoJsResourceUri);
ResourceHelper.renderScriptLink(context, springDojoJsResourceUri);
}
}
@@ -72,10 +68,10 @@ public class DojoDecorationRenderer extends BaseSpringJavascriptDecorationRender
UIComponent advisedChild = (UIComponent) component.getChildren().get(0);
resourceHelper.renderDojoInclude(context, ((DojoDecoration) component).getDojoComponentType());
ResourceHelper.renderDojoInclude(context, ((DojoDecoration) component).getDojoComponentType());
ResourceHelper.beginScriptBlock(context);
writer.startElement(SCRIPT_ELEMENT, component);
writer.writeAttribute("type", "text/javascript", null);
StringBuffer script = new StringBuffer();
script.append(" Spring.addDecoration(new Spring.ElementDecoration({ ");
script.append(" elementId : '" + advisedChild.getClientId(context) + "', ");
@@ -94,7 +90,8 @@ public class DojoDecorationRenderer extends BaseSpringJavascriptDecorationRender
script.append(" }}));");
writer.writeText(script, null);
writer.endElement(SCRIPT_ELEMENT);
ResourceHelper.endScriptBlock(context);
}
protected String getNodeAttributesAsString(FacesContext context, UIComponent component) {

View File

@@ -35,10 +35,8 @@ public class DojoStyleRenderer extends Renderer {
private static final String dijitTheme = "tundra";
private static final ResourceHelper resourceHelper = new ResourceHelper();
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
resourceHelper.renderStyleLink(context, dijitThemePath + dijitTheme + "/" + dijitTheme + ".css");
ResourceHelper.renderStyleLink(context, dijitThemePath + dijitTheme + "/" + dijitTheme + ".css");
}
}

View File

@@ -32,6 +32,7 @@ import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;
import org.springframework.beans.BeanUtils;
import org.springframework.faces.ui.resource.ResourceHelper;
import org.springframework.faces.webflow.JsfUtils;
import org.springframework.util.Assert;
@@ -102,9 +103,9 @@ public class ProgressiveCommandLinkRenderer extends ProgressiveCommandButtonRend
button.encodeEnd(context);
// Now render the link's HTML into a javascript variable
ResourceHelper.beginScriptBlock(context);
ResponseWriter writer = context.getResponseWriter();
writer.startElement("script", component);
writer.writeAttribute("type", "text/javascript", null);
String scriptVarStart = "var " + component.getClientId(context).replaceAll(":", "_") + "_link = \"";
writer.writeText(scriptVarStart, null);
writer = new DoubleQuoteEscapingWriter(writer);
@@ -133,16 +134,17 @@ public class ProgressiveCommandLinkRenderer extends ProgressiveCommandButtonRend
writer.writeText(scriptVarEnd, null);
decorationParams.append(", linkHtml : " + component.getClientId(context).replaceAll(":", "_") + "_link");
writer.endElement("script");
ResourceHelper.endScriptBlock(context);
}
decorationParams.append("}");
StringBuffer advisorScript = new StringBuffer();
advisorScript.append("Spring.addDecoration(new Spring.CommandLinkDecoration(" + decorationParams.toString()
+ "));");
writer.startElement("script", component);
ResourceHelper.beginScriptBlock(context);
writer.writeText(advisorScript, null);
writer.endElement("script");
ResourceHelper.endScriptBlock(context);
}
protected String[] getAttributesToRender(UIComponent component) {

View File

@@ -37,18 +37,16 @@ import org.springframework.faces.ui.resource.ResourceHelper;
*/
public class ResourceGroupRenderer extends Renderer {
private static final ResourceHelper resourceHelper = new ResourceHelper();
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
if (component.getChildCount() > 0) {
resourceHelper.beginCombineStyles(context);
ResourceHelper.beginCombineStyles(context);
}
}
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
if (component.getChildCount() > 0) {
resourceHelper.endCombineStyles(context);
ResourceHelper.endCombineStyles(context);
}
}
}

View File

@@ -37,8 +37,6 @@ import org.springframework.util.Assert;
*/
public class ResourceRenderer extends Renderer {
private static final ResourceHelper resourceHelper = new ResourceHelper();
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
String resourcePath = (String) component.getAttributes().get("path");
Assert.hasText(resourcePath, "Resource component " + component.getClientId(context) + " is missing a path.");
@@ -46,7 +44,7 @@ public class ResourceRenderer extends Renderer {
resourcePath = "/" + resourcePath;
component.getAttributes().put("path", resourcePath);
}
resourceHelper.renderResource(context, resourcePath);
ResourceHelper.renderResource(context, resourcePath);
}
}

View File

@@ -24,6 +24,8 @@ import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;
import org.springframework.faces.ui.resource.ResourceHelper;
/**
* {@link Renderer} for the {@code <sf:validateAllOnClick>} tag.
*
@@ -32,8 +34,6 @@ import javax.faces.render.Renderer;
*/
public class ValidateAllRenderer extends BaseSpringJavascriptDecorationRenderer {
private static final String SCRIPT_ELEMENT = "script";
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
ResponseWriter writer = context.getResponseWriter();
@@ -48,12 +48,13 @@ public class ValidateAllRenderer extends BaseSpringJavascriptDecorationRenderer
UIComponent advisedChild = (UIComponent) component.getChildren().get(0);
writer.startElement(SCRIPT_ELEMENT, component);
writer.writeAttribute("type", "text/javascript", null);
ResourceHelper.beginScriptBlock(context);
StringBuffer script = new StringBuffer();
script.append("Spring.addDecoration(new Spring.ValidateAllDecoration({" + "event : 'onclick', "
+ "elementId : '" + advisedChild.getClientId(context) + "'}));");
writer.writeText(script, null);
writer.endElement(SCRIPT_ELEMENT);
ResourceHelper.endScriptBlock(context);
}
}

View File

@@ -43,13 +43,23 @@ public class ResourceHelper {
private static final String COMBINED_RESOURCES_KEY = "org.springframework.faces.CombinedResources";
private static final String SCRIPT_BLOCK_ESCAPE_BEGIN = "<!--//--><![CDATA[//><!--\n";
private static final String SCRIPT_BLOCK_ESCAPE_END = "\n//--><!]]>";
private static final String SCRIPT_ELEMENT = "script";
private ResourceHelper() {
}
/**
* Renders either a script or style resource depending on the resourcePath
* @param facesContext
* @param resourcePath
* @throws IOException
*/
public void renderResource(FacesContext facesContext, String resourcePath) throws IOException {
public static void renderResource(FacesContext facesContext, String resourcePath) throws IOException {
if (resourcePath.endsWith(".js")) {
renderScriptLink(facesContext, resourcePath);
} else if (resourcePath.endsWith(".css")) {
@@ -63,7 +73,7 @@ public class ResourceHelper {
* @param scriptPath
* @throws IOException
*/
public void renderScriptLink(FacesContext facesContext, String scriptPath) throws IOException {
public static void renderScriptLink(FacesContext facesContext, String scriptPath) throws IOException {
renderScriptLink(facesContext, scriptPath, Collections.EMPTY_MAP);
}
@@ -74,12 +84,13 @@ public class ResourceHelper {
* @param attributes - a map of additional attributes to render on the script tag
* @throws IOException
*/
public void renderScriptLink(FacesContext facesContext, String scriptPath, Map attributes) throws IOException {
public static void renderScriptLink(FacesContext facesContext, String scriptPath, Map attributes)
throws IOException {
if (alreadyRendered(facesContext, scriptPath)) {
return;
}
ResponseWriter writer = facesContext.getResponseWriter();
writer.startElement("script", null);
writer.startElement(SCRIPT_ELEMENT, null);
writer.writeAttribute("type", "text/javascript", null);
Iterator i = attributes.keySet().iterator();
while (i.hasNext()) {
@@ -88,7 +99,7 @@ public class ResourceHelper {
}
String src = facesContext.getExternalContext().getRequestContextPath() + "/resources" + scriptPath;
writer.writeAttribute("src", src, null);
writer.endElement("script");
writer.endElement(SCRIPT_ELEMENT);
markRendered(facesContext, scriptPath);
}
@@ -98,7 +109,7 @@ public class ResourceHelper {
* @param cssPath
* @throws IOException
*/
public void renderStyleLink(FacesContext facesContext, String cssPath) throws IOException {
public static void renderStyleLink(FacesContext facesContext, String cssPath) throws IOException {
if (alreadyRendered(facesContext, cssPath)) {
return;
} else if (isCombineStyles(facesContext)) {
@@ -121,33 +132,33 @@ public class ResourceHelper {
* @param module
* @throws IOException
*/
public void renderDojoInclude(FacesContext facesContext, String module) throws IOException {
public static void renderDojoInclude(FacesContext facesContext, String module) throws IOException {
if (alreadyRendered(facesContext, module)) {
return;
}
ResponseWriter writer = facesContext.getResponseWriter();
writer.startElement("script", null);
writer.startElement(SCRIPT_ELEMENT, null);
writer.writeAttribute("type", "text/javascript", null);
writer.writeText("dojo.require('" + module + "');", null);
writer.endElement("script");
writer.endElement(SCRIPT_ELEMENT);
markRendered(facesContext, module);
}
public void beginCombineStyles(FacesContext facesContext) {
public static void beginCombineStyles(FacesContext facesContext) {
List combinedResources = new ArrayList();
facesContext.getExternalContext().getRequestMap().put(COMBINED_RESOURCES_KEY, combinedResources);
}
private boolean isCombineStyles(FacesContext facesContext) {
private static boolean isCombineStyles(FacesContext facesContext) {
return facesContext.getExternalContext().getRequestMap().containsKey(COMBINED_RESOURCES_KEY);
}
private void addStyle(FacesContext facesContext, String stylePath) {
private static void addStyle(FacesContext facesContext, String stylePath) {
List combinedResources = (List) facesContext.getExternalContext().getRequestMap().get(COMBINED_RESOURCES_KEY);
combinedResources.add(stylePath);
}
public void endCombineStyles(FacesContext facesContext) throws IOException {
public static void endCombineStyles(FacesContext facesContext) throws IOException {
List combinedResources = (List) facesContext.getExternalContext().getRequestMap()
.remove(COMBINED_RESOURCES_KEY);
StringBuffer combinedPath = new StringBuffer();
@@ -164,7 +175,20 @@ public class ResourceHelper {
renderStyleLink(facesContext, combinedPath.toString());
}
private void markRendered(FacesContext facesContext, String scriptPath) {
public static void beginScriptBlock(FacesContext facesContext) throws IOException {
ResponseWriter writer = facesContext.getResponseWriter();
writer.startElement(SCRIPT_ELEMENT, null);
writer.writeAttribute("type", "text/javascript", null);
writer.writeText(SCRIPT_BLOCK_ESCAPE_BEGIN, null);
}
public static void endScriptBlock(FacesContext facesContext) throws IOException {
ResponseWriter writer = facesContext.getResponseWriter();
writer.writeText(SCRIPT_BLOCK_ESCAPE_END, null);
writer.endElement(SCRIPT_ELEMENT);
}
private static void markRendered(FacesContext facesContext, String scriptPath) {
Set renderedResources = (Set) facesContext.getExternalContext().getRequestMap().get(RENDERED_RESOURCES_KEY);
if (renderedResources == null) {
renderedResources = new HashSet();
@@ -173,7 +197,7 @@ public class ResourceHelper {
renderedResources.add(scriptPath);
}
private boolean alreadyRendered(FacesContext facesContext, String scriptPath) {
private static boolean alreadyRendered(FacesContext facesContext, String scriptPath) {
Set renderedResources = (Set) facesContext.getExternalContext().getRequestMap().get(RENDERED_RESOURCES_KEY);
return renderedResources != null && renderedResources.contains(scriptPath);
}

View File

@@ -10,8 +10,6 @@ import org.springframework.faces.webflow.JSFMockHelper;
public class FlowResourceHelperTests extends TestCase {
ResourceHelper resourceHelper = new ResourceHelper();
StringWriter writer = new StringWriter();
JSFMockHelper jsf = new JSFMockHelper();
@@ -31,8 +29,8 @@ public class FlowResourceHelperTests extends TestCase {
String scriptPath = "/dojo/dojo.js";
String expectedUrl = "null/resources/dojo/dojo.js";
resourceHelper.renderScriptLink(jsf.facesContext(), scriptPath);
resourceHelper.renderScriptLink(jsf.facesContext(), scriptPath);
ResourceHelper.renderScriptLink(jsf.facesContext(), scriptPath);
ResourceHelper.renderScriptLink(jsf.facesContext(), scriptPath);
String expectedOutput = "<script type=\"text/javascript\" src=\"" + expectedUrl + "\"/>";
@@ -45,8 +43,8 @@ public class FlowResourceHelperTests extends TestCase {
String scriptPath = "/dijit/themes/dijit.css";
String expectedUrl = "null/resources/dijit/themes/dijit.css";
resourceHelper.renderStyleLink(jsf.facesContext(), scriptPath);
resourceHelper.renderStyleLink(jsf.facesContext(), scriptPath);
ResourceHelper.renderStyleLink(jsf.facesContext(), scriptPath);
ResourceHelper.renderStyleLink(jsf.facesContext(), scriptPath);
String expectedOutput = "<link type=\"text/css\" rel=\"stylesheet\" href=\"" + expectedUrl + "\"/>";

File diff suppressed because one or more lines are too long

View File

@@ -248,7 +248,7 @@ dojo.declare("Spring.RemotingHandler", Spring.AbstractRemotingHandler, {
for (var i=0; i<scriptNodes.length; i++)
{
var script = (scriptNodes[i].match(matchOne) || ['','',''])[2];
script = script.replace(/<!--/mg,'').replace(/\/\/-->/mg,'');
script = script.replace(/<!--/mg,'').replace(/\/\/-->/mg,'').replace(/<!\[CDATA\[(\/\/>)*/mg,'').replace(/(<!)*\]\]>/mg,'');
extractedScriptNodes.push(script);
}
}