... without changing any of the existing code
You can't. At least, not without being tight coupled to a specific implementation (Mojarra or MyFaces). The alternative would be to bite the bullet and replace all <ui:include>
and <ui:define>
by <my:include>
and <my:define>
. Facelets is not fully abstracted/standardized into JSF specification yet. There's only a Facelet cache factory, but no Facelet context factory, otherwise it'd have been easy. Generally, forget about customizing <ui:xxx>
tags in an abstract way. You'd need to hack the implementation.
Given that you're using Mojarra 2.1.19, you'd need to copypaste its com.sun.faces.facelets.impl.DefaultFaceletContext
class into your web application project, maintaining its com.sun.faces.facelets.impl
package. Classes in WAR have higher classloading precedence than those in WAR's /WEB-INF/lib
and server's /lib
. So this one in your WAR would be used instead.
Given that you'd like to achieve the same as asked in Customize ui:include rendering to add prefix/postfix on <ui:include>
and <ui:define>
:
Example, supposing a blank file.xhtml:
Input
<ui:include src="file.xhtml" />
Output
<!-- START file.xhtml -->
<!-- END file.xhtml -->
Here's how you can achieve it by editing the copypasted DefaultFaceletContext
class:
Add a helper method to the class which creates a comment component (which is just a plain output text component).
private static UIComponent createComment(String comment) {
UIOutput text = new UIOutput();
text.setValue("\n<!-- " + comment + " -->\n");
return text;
}
Extend the oneliner method includeFacelet(UIComponent, String)
at line 199 as below:
parent.getChildren().add(createComment("START INCLUDE " + relativePath));
facelet.include(this, parent, relativePath);
parent.getChildren().add(createComment("END INCLUDE " + relativePath));
Extend the includeDefinition(UIComponent, String)
around line 366 with client.apply(this, parent, name)
as below:
int start = parent.getChildCount();
found = client.apply(this, parent, name);
if (found) {
parent.getChildren().add(start, createComment("START DEFINE " + name));
parent.getChildren().add(createComment("END DEFINE " + name));
}
During testing I however found a caveat. I have my HTML <title>
templated like below:
<h:head>
<title><ui:insert name="title">#{view.viewId}</ui:insert></title>
</h:head>
Comments thus also end up inside <title>
element. Unfortunately comments in a HTML title is invalid syntax (only PCDATA
allowed) and they are interpreted literally and thus show up in the document title. You might want to create a blacklist based on name
of the definition or perhaps the parent
.