I am using JSF 2.0, and am looking for a means to include all the javascripts from a given folder on a page, i.e. do something like
I didn't test this, but if wildcards are not accepted, you could fetch the filelist via java code in a backing bean, and insert them into head using c:forEach
or ui:repeat
like:
<ui:repeat value="#{bean.files}" var="file">
<h:outputScript library="javascript" name="#{file}" target="head" />
</ui:repeat>
Note that you cannot give absolute paths to h:outputScript
but you must extract the prefix from them (the part the preceeds the JSF resources path).
Nice idea. This is not supported by the JSF API, but it's in theory possible with a custom script renderer. I played somewhat around it and it's indeed possible. Just create a MultiScriptRenderer
which extends ScriptRenderer
and override encodeEnd() to check if the name
attribute contains the *
wildcard and then handle accordingly by scanning for files matching this pattern in the resources folder.
Here's a kickoff example:
package com.example;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import com.sun.faces.renderkit.html_basic.ScriptRenderer;
public class MultiScriptRenderer extends ScriptRenderer {
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
Map<String, Object> attributes = component.getAttributes();
String name = (String) attributes.get("name");
if (name.contains("*")) {
String pattern = name.replace(".", "\\.").replace("*", ".*");
String library = (String) attributes.get("library");
File root = new File(context.getExternalContext().getRealPath("/resources/" + (library != null ? library : "")));
for (File file : root.listFiles()) {
if (file.getName().matches(pattern)) {
attributes.put("name", file.getName());
super.encodeEnd(context, component);
}
}
attributes.put("name", name); // Put original name back. You never know.
} else {
super.encodeEnd(context, component);
}
}
}
Register it in faces-config.xml
as follows (Sorry, @FacesRenderer annotation isn't going to work until it's fixed in JSF 2.2 for this specific corner case, see also JSF issue 1748):
<render-kit>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.resource.Script</renderer-type>
<renderer-class>com.example.MultiScriptRenderer</renderer-class>
</renderer>
</render-kit>
Works fine on Mojarra 2.0.3 here. You can use patterns like *.js
and prefix*.js
. The particular code example is only tight coupled to a specific JSF implementation to save code boilerplate. It also requires that the WAR is expanded on deploy, otherwise browsing the directory by File#listFiles()
won't be possible (which thus excludes certain (older) servletcontainer versions/configurations). For other JSF implementations you'll have to extend its ScriptRenderer
instead, or write a whole new one if you want to be implementation independent (which should be pretty simple though, just look at standard ScriptRenderer
source if you stucks).